【洛谷P2577】[ZJOI2005]午餐
午餐
DP题都辣么毒瘤的么。。
首先,看一下题解
我们就有了思路:
贪心:显然,让吃饭慢的先打饭,sort一遍(证明?不存在的。。
DP:f[i][j][k]表示前i个人,窗口1的打饭时间为j,窗口2的打饭时间为k的最早吃完饭的时间
对于每个人,有两种方案:1.在窗口1打饭 2.在窗口2打饭 (废话)
a[i].ti为第i个人的打饭时间,a[i].t2为第i个人的吃饭时间
f[i][j][k]=max(f[i-1][j-a[i].t1][k],j+a[i].t2); //排在第一个窗口
f[i][j][k]=max(f[i-1][j][k-a[i].t1],k+a[i].t2); //排在第二个窗口
优化:我们发现,知道j时,k可以用t1的前缀和求出来,这样可以减一维
i可以滚动数组滚掉
f[j]=max(f[j-a[i].t1],j+a[i].t2);
f[j]=max(f[j],sum-j+a[i].t2);
#include<algorithm> #include<cstdio> #define INF 0x3f3f3f3f #define re register #define N 220 int n,f[80010],ans,sum; struct NODE{ int t1,t2; } a[N]; inline bool cmp(NODE x,NODE y) { return x.t2>y.t2; } inline int max(int x,int y) { return x>y?x:y; } inline int min(int x,int y) { return x<y?x:y; } inline int read(){ int x=0; char c=getchar(); while(c<'0'||c>'9') c=getchar(); while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); } return x; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++){ a[i].t1=read(); a[i].t2=read(); } std::sort(a+1,a+1+n,cmp); std::fill(f,f+80001,INF); f[0]=0; int c1,c2; for(int i=1;i<=n;i++){ sum+=a[i].t1; for(int j=sum;j>=0;j--){ if(j>=a[i].t1) c1=max(f[j-a[i].t1],j+a[i].t2); else c1=INF; c2=max(f[j],sum-j+a[i].t2); f[j]=min(c1,c2); } } ans=INF; for(int i=1;i<=sum;i++) ans=min(ans,f[i]); printf("%d\n",ans); return 0; }