1. 程式人生 > >洛谷 2577 [ZJOI2005]午餐——序列dp

洛谷 2577 [ZJOI2005]午餐——序列dp

https div name set 題目 namespace tchar new ans

題目:https://www.luogu.org/problemnew/show/P2577

可以從只有一個窗口的角度思考出一個貪心結論。就是應當按吃飯時間(不算打飯時間)從大到小排序。這樣交換相鄰兩個不會使答案更優,因為交換的話對其他人無影響,而吃飯時間長的那個人打到飯的時間也靠後了。

記錄第一個窗口打完飯的時間在狀態裏。已知前 i 個人打飯時間和,能算出來第二個窗口打完飯的時間。所以值就可以記錄總共的最晚結束時間了!也因為最晚結束時間對於打完飯的時間不是關系很緊密的,所以需要把第一個窗口的所有可能的打完飯的時間對應的結束時間記錄下來。

#include<iostream>
#include
<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=205,M=N*N,INF=0x3f3f3f3f; int n,f[2][M],ans=INF,lm; struct Node{ int a,b; bool operator< (const Node &v) const {return b>v.b;} }t[N]; int rdn() { int ret=0,fx=1; char ch=getchar();
while(ch>9||ch<0){if(ch==-)fx=-1; ch=getchar();} while(ch>=0&&ch<=9) ret=(ret<<3)+(ret<<1)+ch-0,ch=getchar(); return ret*fx; } int main() { n=rdn(); for(int i=1;i<=n;i++) t[i].a=rdn(),t[i].b=rdn(); sort(t+1,t+n+1); memset(f,0x3f,sizeof
f); f[0][0]=0; for(int i=1,u=1,v=0;i<=n;i++,u=!u,v=!v) { lm+=t[i].a; for(int j=0,k1,k2;j<=lm;j++) { if(f[v][j])f[u][j]=max(f[v][j],lm-j+t[i].b); if(j>=t[i].a) f[u][j]=min(f[u][j],max(f[v][j-t[i].a],j+t[i].b)); } } int d=(n&1); for(int j=0;j<=lm;j++) ans=min(ans,f[d][j]); printf("%d\n",ans); return 0; }

洛谷 2577 [ZJOI2005]午餐——序列dp