【洛谷P2577】[ZJOI2005]午餐

本文介绍了一种使用动态规划解决午餐问题的方法。该问题的目标是在两个打饭窗口中选择最优排队方式,使得所有人完成就餐所需时间最短。文章通过代码详细展示了如何实现DP算法,并进行了适当优化。

午餐

题目链接

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\n",ans);
    return 0;
}

 

转载于:https://www.cnblogs.com/yjkhhh/p/9414833.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值