poj 2938 Economic Phone Calls

2014-11-24 10:52:29 · 作者: · 浏览: 0

此题的核心就是选择,按时间顺序进行选择的话,可以发现每次选择只和当前选择的集合中时间最晚的电话有关。

所以可以dp。

令f[i][j]为处理了前i个电话,当前选择的电话中最晚的电话为j时,选择的最少电话数。

对于i而言,如果选择i,则有f[i][i]=min{f[i-1][j]},其中1<=j

同时,如果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
#include
#include
#include
#include
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 if (day>y.day) return true;
if (day if (h>y.h) return true;
if (h 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 if (f[i-1][j] {
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 if (f[i-1][j] {
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;
for (i=1;i<=n;i++)
ans=min(ans,f[n][i]);
if (ans>=INF) ans=n;
printf("%d\n",ans);
}
}