方案如下:
窗口1: 窗口2:
7 7 1 3
6 4 8 5
2 2
【限制】
所有输入数据均为不超过200的正整数。
题解:首先自己讨论一下就能知道,如果只有一个队列,那么一定是让吃饭时间慢的先打饭。那么如果有两个队列,那么其中的每一个都一定是按吃饭时间递减的,所以我们先将所有人按吃饭时间排序。
然后设f[i][j][k]表示前i个人,A队列总等待时间为j,B队列总等待时间为k,所需要的最小总时间。下一步比较神,用sum[i]表示前i个人等待时间的前缀和,则j+k=sum[i],所以我们可以优化掉一维。
然后就容易DP了。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n,ans;
int f[1010][260][17],cnt[260],T[1010],B[1010];
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘)f=-f; gc=getchar();}
while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar();
return ret*f;
}
int calc(int a,int b)
{
if(a<=0) return 0;
return T[a]^T[b];
}
void work()
{
memset(f,0x3f,sizeof(f));
n=rd();
int i,j,k,l;
for(i=1;i<=n;i++) T[i]=rd(),B[i]=min(rd(),n-i);
f[0][0][8]=0;
for(i=0;i<n;i++) for(j=0;j<(1<<min(n-i,8));j++) for(k=max(8-i,0);k<=min(n-i,8)+8;k++)
{
if(j&1)
{
f[i+1][j>>1][k-1]=min(f[i+1][j>>1][k-1],f[i][j][k]);
continue;
}
int lim=min(n-i,8);
for(l=1;l<=lim;l++) if(!(j&(1<<(l-1))))
{
f[i][j|(1<<(l-1))][l+8]=min(f[i][j|(1<<(l-1))][l+8],f[i][j][k]+calc(i+k-8,i+l));
lim=min(lim,l+B[i+l]);
}
}
ans=1<<30;
for(i=max(8-n,0);i<=8;i++) ans=min(ans,f[n][0][i]);
printf("%d\n",ans);
}
int main()
{
int T=rd();
while(T--) work();
return 0;
}//1 2 5 0 4 0
【BZOJ1899】[Zjoi2004]Lunch 午餐 贪心+DP
原文:http://www.cnblogs.com/CQzhangyu/p/7468822.html