【洛谷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
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/yjkhhh/p/9414833.html