dp+排序。
传送门:GO
用f[i][j]表示第i个人在j时间在1号窗口打餐,最后吃完的最短时间。
为什么这样设呢?因为根据1号窗口打餐,是可以求出2号窗口的具体数值的,用一个前缀和储存打餐时间,那么
f[i][j]=min(f[i][j],max(f[i-1][j-a[i].get],j+a[i].eat))
这条表示上次在1号打餐的情况的转移。
f[i][j]=min(f[i][j],max(f[i-1][j],sum[i]-j+a[i].eat))
这条就是在2号窗口打餐的情况转移。
还要先将吃饭的时间大到小排序,因为对于排好的队伍,无论怎么调整,打饭时间是确定的,让吃饭时间长的越早吃一定最优。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int read(){ 4 int x=0,f=1; 5 char c=getchar(); 6 while(!isdigit(c)){ 7 if(c=='-') f=-1; 8 c=getchar(); 9 } 10 while(isdigit(c)){ 11 x=x*10+c-'0'; 12 c=getchar(); 13 } 14 return x*f; 15 } 16 const int N=210; 17 int n; 18 struct men{ 19 int get,eat; 20 }a[N]; 21 bool cmp(men t1,men t2){ 22 return t1.eat>t2.eat; 23 } 24 int f[N][N*N],sum[N]; 25 int main(){ 26 n=read(); 27 for(int i=1;i<=n;i++){ 28 a[i]=(men){read(),read()}; 29 } 30 sort(a+1,a+n+1,cmp); 31 for(int i=1;i<=n;i++){ 32 sum[i]=sum[i-1]+a[i].get; 33 } 34 memset(f,0x3f,sizeof(f)); 35 f[0][0]=0; 36 for(int i=1;i<=n;i++){ 37 for(int j=0;j<=sum[i];j++){ 38 if(j>=a[i].get) f[i][j]=min(f[i][j],max(f[i-1][j-a[i].get],j+a[i].eat)); 39 f[i][j]=min(f[i][j],max(f[i-1][j],sum[i]-j+a[i].eat)); 40 } 41 } 42 int ans=1e9; 43 for(int i=0;i<=sum[n];i++) ans=min(ans,f[n][i]); 44 printf("%d",ans); 45 return 0; 46 }