洛谷P2577 [zjoi2004]午餐---贪心+dp
题目链接:https://www.luogu.com.cn/problem/P2577
简单题意:两个窗口打饭,每个人有打饭和吃饭时间,求最快全部吃完的时间
让吃饭时间长的先打饭,应该比较容易想到,不管窗口数量是多少。但是之后就开始胡乱设计状态了。一开始想了个sb状态:dp[i][1/2]表示轮到第i个人,选择窗口1/2的最小时间,发现根本写不出来方程......
正解是设 f[i][j]表示前i个人在窗口1打饭时间为j,吃完饭的最早时间。有点难想到,而且这个状态怎么只考虑了一个窗口?其实原方程是 f[i][j][k]表示前i个人,在1窗口打饭时间为j,2窗口为k的最早时间,由于j+k是定值,所以可以去掉一维。转移方程看代码吧,其实有点像个背包问题(细节:有可能第i个人吃完饭了,之前的人还没吃完)。另外这个初始化纠结了一会,一开始总是想前i个人如果打饭时间不能为j怎么办,其实全初始化为inf就行了
#include<bits/stdc++.h> #define ll long long using namespace std; struct st{int c,d;}a[210]; int n,i,j,k,ans,f[210][210*210],sum[210]; bool cmp(st p,st q){return p.c>q.c;} //f[i][j]: 前i个人在窗口1打饭时间为j的最小结束时间 int main(){ cin>>n; for (i=1;i<=n;i++) cin>>a[i].d>>a[i].c; sort(a+1,a+n+1,cmp); //吃饭时间降序 for (i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].d; memset(f,0x3f,sizeof(f)); f[0][0]=0; //* for (i=1;i<=n;i++) for (j=0;j<=sum[i];j++){ if (j-a[i].d>=0) f[i][j]=max(j+a[i].c,f[i-1][j-a[i].d]); //i放在队1 f[i][j]=min(f[i][j],max(sum[i]-j+a[i].c,f[i-1][j])); //i放在队2 } ans=1e9; for (i=0;i<=sum[n];i++) ans=min(ans,f[n][i]); cout<<ans<<endl; return 0; }