【LuoguP2577】[ZJOI2005]午餐

题目链接

题目描述

上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂。这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭。由于每个人的口味(以及胃口)不同,所以他们要吃的菜各有不同,打饭所要花费的时间是因人而异的。另外每个人吃饭的速度也不尽相同,所以吃饭花费的时间也是可能有所不同的。

THU ACM小组的吃饭计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排队打饭,二号队伍到二号窗口去排队打饭。每个人打完饭后立刻开始吃,所有人都吃完饭后立刻集合去六教地下室进行下午的训练。

现在给定了每个人的打饭时间和吃饭时间,要求安排一种最佳的分队和排队方案使得所有人都吃完饭的时间尽量早。

假设THU ACM小组在时刻0到达十食堂,而且食堂里面没有其他吃饭的同学(只有打饭的师傅)。每个人必须而且只能被分在一个队伍里。两个窗口是并行操作互不影响的,而且每个人打饭的时间是和窗口无关的,打完饭之后立刻就开始吃饭,中间没有延迟。

现在给定N个人各自的打饭时间和吃饭时间,要求输出最佳方案下所有人吃完饭的时刻。

题解

若只有一个队伍,—>刘汝佳蓝书 突击战
按吃饭时间排序,吃得久的先打饭。

现在有两个队伍怎么办,那么确定其中一个队伍的情况不就只有一个队伍了吗。
我们发现打饭是分别进行的,吃饭是同时进行的,显然我们只好维护打饭时间,不然没得转移了。
d p [ i ] [ j ] i j
是不是很像背包?代码也和背包差不多。

对于一个人,要么到队1,要么到队2。
那么分别讨论即可,具体看代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
const int N=201;
#define Set(a,b) memset(a,b,sizeof(a))
inline int read()
{
    int x=0;char ch=getchar();int t=1;
    for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
    return x*t;
}
struct person{
    int rec,eat;
    inline bool operator <(person b)const{
        return (eat>b.eat)||(eat==b.eat&&rec>b.rec);
    }
}a[N];
int n;
int dp[N*N+N];//开了滚动数组

int main()
{
    n=read();int sum=0;
    for(register int i=1;i<=n;i++) a[i].rec=read(),a[i].eat=read();
    Set(dp,127/3);
    register int INF=dp[0];
    sort(a+1,a+1+n);
    dp[0]=0;
    for(register int i=1;i<=n;i++){
        for(register int j=sum;j>=0;j--){
            dp[j+a[i].rec]=min(dp[j+a[i].rec],max(dp[j],j+a[i].rec+a[i].eat));//到第一队
            dp[j]=max(dp[j],sum-j+a[i].rec+a[i].eat);//第一队等待时间为j,那么第二队等待时间即为sum-j
        }
        sum+=a[i].rec;
    }
    register int ans=INF;
    for(register int i=1;i<=sum;i++) ans=min(ans,dp[i]);
    printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/element_hero/article/details/79393346
今日推荐