http://www.elijahqi.win/archives/543
描述
上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂。这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭。由于每个人的口味(以及胃口)不同,所以他们要吃的菜各有不同,打饭所要花费的时间是因人而异的。另外每个人吃饭的速度也不尽相同,所以吃饭花费的时间也是可能有所不同的。
THU ACM小组的吃饭计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排队打饭,二号队伍到二号窗口去排队打饭。每个人打完饭后立刻开始吃,所有人都吃完饭后立刻集合去六教地下室进行下午的训练。
现在给定了每个人的打饭时间和吃饭时间,要求安排一种最佳的分队和排队方案使得所有人都吃完饭的时间尽量早。
假设THU ACM小组在时刻0到达十食堂,而且食堂里面没有其他吃饭的同学(只有打饭的师傅)。每个人必须而且只能被分在一个队伍里。两个窗口是并行操作互不影响的,而且每个人打饭的时间是和窗口无关的,打完饭之后立刻就开始吃饭,中间没有延迟。
现在给定N个人各自的打饭时间和吃饭时间,要求输出最佳方案下所有人吃完饭的时刻。
格式
输入格式
第一行一个整数N,代表总共有N个人。
以下N行,每行两个整数 Ai,Bi。依次代表第i个人的打饭时间和吃饭时间。
输出格式
一个整数T,代表所有人吃完饭的最早时刻。
样例1
样例输入1
5
2 2
7 7
1 3
6 4
8 5
Copy
样例输出1
17
Copy
提示
所有输入数据均为不超过200的正整数。
方案如下:
窗口1: 窗口2:
7 7 1 3
6 4 8 5
2 2
来源
TJU
首先有点贪心的想法,按照吃饭时间从大到小排列
方程设f[i][j] i为前i个人在一号窗口打饭时间为j 的情况下 最后都吃完饭时花费时间最小为多少
看下转移方程
f[i][j]=min(f[i][j],max(f[i-1][j],d[i-1]-j+data[i].a+data[i].b)); //maxf[i-1][j] (壹号窗口的时间) d[i-1]-j+data[i].a+data[i].b(二号窗口的时间)
if (data[i].a<=j){ f[i][j]=min(f[i][j],max(f[i-1][j-data[i].a],j+data[i].b)); } 或者是 在壹号窗口排队导致时间花到了j这么多
#include<cstdio>
#include<algorithm>
#include<cstring>
#define inf 0x7fffffff
#define N 220
struct node{
int a, b;
}data[N];
inline bool cmp(node a ,node b){
return a.b>b.b;
}
inline int min(int x,int y){
return x<y?x:y;
}
inline int max(int x,int y){
return x>y?x:y;
}
int n,d[N],f[N][N*N];
int main(){
freopen("bzoj1899.in","r",stdin);
//freopen("bzoj1899.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d%d",&data[i].a,&data[i].b);
std::sort(data+1,data+n+1,cmp);
for (int i=1;i<=n;++i) d[i]=d[i-1]+data[i].a;
memset(f,0x3f,sizeof(f));f[0][0]=0;
for (int i=1;i<=n;++i)
for (int j=0;j<=d[i];++j){
f[i][j]=min(f[i][j],max(f[i-1][j],d[i-1]-j+data[i].a+data[i].b));
if (data[i].a<=j){
f[i][j]=min(f[i][j],max(f[i-1][j-data[i].a],j+data[i].b));
}
}
int ans=inf;
for (int i=1;i<=d[n];++i) ans=min(ans,f[n][i]);
printf("%d",ans);
return 0;
}