[BZOJ1899]Lunch 午餐(DP)
阿新 • • 發佈:2018-05-11
print 前綴 zoj div IE || sort operator while
[BZOJ1899]
首先有個很貪心的思路,吃飯時間長的最先打飯為最優,所以開始先排個序
然後考慮DP,我們不需要知道某個人在哪個對,只要關註總的時間就行了
肯定需要一維表示當前同學編號,還需要表示某個窗口的打飯時間,如果知道其中一個窗口,另一個也可以知道,所以一維就行
那麽用f[i][j]表示前i個同學,第一個窗口打飯總時間為j時的答案
s[i]表示排序後前打飯時間前綴和,a表示打飯時間,b表示吃飯時間
- 當前同學放二號窗口,f[i][j]=min{f[i][j],max(f[i-1][j],sum[i-1]-j+A[i].a+A[i].b)}
- 放1號窗口,f[i][j]=min{f[i][j],max(f[i-1][j-A[i].a],j+A[i].b)}
Code
#include <cstdio> #include <algorithm> #include <cstring> #define N 210 using namespace std; struct info{ int a,b; friend bool operator <(info a,info b){ return a.b>b.b; } }A[N]; int n,Ans,s[N],f[N][N*N],sum; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } int main(){ n=read(); for(int i=1;i<=n;++i) A[i].a=read(),A[i].b=read(); sort(A+1,A+n+1); for(int i=1;i<=n;++i) s[i]=s[i-1]+A[i].a; memset(f,0x3f,sizeof(f));f[0][0]=0; for(int i=1;i<=n;++i) for(int j=0;j<=s[i];++j){ f[i][j]=min(f[i][j],max(f[i-1][j],s[i-1]-j+A[i].a+A[i].b)); if(j>=A[i].a) f[i][j]=min(f[i][j],max(f[i-1][j-A[i].a],j+A[i].b)); } Ans=1e9; for(int i=0;i<=s[n];++i) Ans=min(Ans,f[n][i]); printf("%d\n",Ans); return 0; }
[BZOJ1899]Lunch 午餐(DP)