poj 2938 Economic Phone Calls
此题的核心就是选择,按时间顺序进行选择的话,可以发现每次选择只和当前选择的集合中时间最晚的电话有关。
所以可以dp。
令f[i][j]为处理了前i个电话,当前选择的电话中最晚的电话为j时,选择的最少电话数。
对于i而言,如果选择i,则有f[i][i]=min{f[i-1][j]},其中1<=j<i,且由j可以判断出i的正确时间。
同时,如果i是今年的电话,则除了上面的转移,还有f[i][i]=min(f[i][i],f[i-1][0]+1)。
如果不选择i,则有f[i][j]=f[i-1][j]。
考虑到可能有前面没有选择的电话,所以这种情况用0表示。
注意边界,如果i是必须选择的,则f[i][0]=INF,否则f[i][0]=f[i-1][0]。
还要注意,最后一个电话才是最近的电话!!!
【代码】
[cpp]
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1003,INF=100000;
struct date
{
int mon,day,h,min;
bool operator >=(const date& y)
{
if (mon>y.mon) return true;
if (mon<y.mon) return false;
if (day>y.day) return true;
if (day<y.day) return false;
if (h>y.h) return true;
if (h<y.h) return false;
if (min>=y.min) return true;
else return false;
}
}a[N];
int f[N][N],y[N];
bool v[N];
int main()
{
int i,j,n,ty,ans;
char ch;
freopen("in","r",stdin);
while (1)
{
scanf("%d\n",&n);
if (n==0) break;
if (n<=10)
{
i=0;
}
for (i=n;i>=1;i--)
{
scanf("%d:%d:%d:%d %d %c\n",&a[i].mon,&a[i].day,&a[i].h,
&a[i].min,&j,&ch);
if (ch=='+') v[i]=true;
else v[i]=false;
}
y[1]=0;
for (i=2;i<=n;i++)
if (a[i]>=a[i-1]) y[i]=y[i-1]+1;
else y[i]=y[i-1];
f[1][1]=1;
if (v[1]) f[1][0]=INF;
else f[1][0]=0;
for (i=2;i<=n;i++)
f[1][i]=INF;
for (i=2;i<=n;i++)
{
for (j=1;j<=n;j++)
f[i][j]=INF;
if (v[i]) f[i][0]=INF;
else f[i][0]=f[i-1][0];
if (v[i])
{
if (y[i]==0) f[i][i]=min(f[i][i],f[i-1][0]+1);
for (j=1;j<i;j++)
if (f[i-1][j]<INF)
{
if (a[i]>=a[j]) ty=y[j]+1;
else ty=y[j];
if (ty!=y[i]) continue;
f[i][i]=min(f[i][i],f[i-1][j]+1);
}
}
else
{
for (j=1;j<=n;j++)
f[i][j]=f[i-1][j];
if (y[i]==0) f[i][i]=min(f[i][i],f[i-1][0]+1);
for (j=1;j<i;j++)
if (f[i-1][j]<INF)
{
if (a[i]>=a[j]) ty=y[j]+1;
else ty=y[j];
if (ty!=y[i]) continue;
f[i][i]=min(f[i][i],f[i-1][j]+1);
}
}
}
ans=INF;
补充:软件开发 , C++ ,