【DP专题】——洛谷P2577午餐

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 }

猜你喜欢

转载自www.cnblogs.com/Nelson992770019/p/11582223.html