BZOJP1899ZJOI2004
老早的一道水题
题意:
上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂。这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭。由于每个人的口味(以及胃口)不同,所以他们要吃的菜各有不同,打饭所要花费的时间是因人而异的。另外每个人吃饭的速度也不尽相同,所以吃饭花费的时间也是可能有所不同的。
THU ACM小组的吃饭计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排队打饭,二号队伍到二号窗口去排队打饭。每个人打完饭后立刻开始吃,所有人都吃完饭后立刻集合去六教地下室进行下午的训练。
现在给定了每个人的打饭时间和吃饭时间,要求安排一种最佳的分队和排队方案使得所有人都吃完饭的时间尽量早。
假设THU ACM小组在时刻0到达十食堂,而且食堂里面没有其他吃饭的同学(只有打饭的师傅)。每个人必须而且只能被分在一个队伍里。两个窗口是并行操作互不影响的,而且每个人打饭的时间是和窗口无关的,打完饭之后立刻就开始吃饭,中间没有延迟。
现在给定N个人各自的打饭时间和吃饭时间,要求输出最佳方案下所有人吃完饭的时刻。
数据范围:
所有输入均小于100
题解:
首先能发现这题给了两个队伍很容易想到dp
但发现人的顺序不知道,思考一下能发现这显然是一个贪心,将吃饭吃的慢的人排在前面
之后就可以dp了,用f[i,j,k]表示第i个人,第1条队伍等待时间为j,第二条队伍等待时间为k,所需的最少结束时间
但发现这是超时的
优化很简单,考虑前缀和sum[i]=j+k,所以只需记录其中一维即可
代码:
#include <bits/stdc++.h>
using namespace std;
#define INF 99999999
struct re{int a,b;}a[300];
bool cmp(re a,re b)
{
return(a.b>b.b);
};
int n,m,f[300][40010],sum[300];
int main(){
freopen("noip.in","r",stdin);
freopen("noip.out","w",stdout);
cin>>n;
for (int i=1;i<=n;i++)
cin>>a[i].a>>a[i].b;
sort(a+1,a+n+1,cmp);
for (int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i].a;
for (int i=0;i<=299;i++)
for (int j=0;j<=40009;j++)
f[i][j]=INF;
f[0][0]=0;
for (int i=1;i<=n;i++)
for (int j=0;j<=sum[i];j++)
{
if (j>=a[i].a) f[i][j]=min(f[i][j],max(f[i-1][j-a[i].a],j+a[i].b));
if (sum[i]-j>=a[i].a) f[i][j]=min(f[i][j],max(f[i-1][j],sum[i]-j+a[i].b));
}
int minn=INF;
for (int i=0;i<=sum[n];i++)
minn=min(minn,f[n][i]);
cout<<minn;
return(0);
}