描述
上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂。这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭。由于每个人的口味(以及胃口)不同,所以他们要吃的菜各有不同,打饭所要花费的时间是因人而异的。另外每个人吃饭的速度也不尽相同,所以吃饭花费的时间也是可能有所不同的。
THU ACM小组的吃饭计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排队打饭,二号队伍到二号窗口去排队打饭。每个人打完饭后立刻开始吃,所有人都吃完饭后立刻集合去六教地下室进行下午的训练。
现在给定了每个人的打饭时间和吃饭时间,要求安排一种最佳的分队和排队方案使得所有人都吃完饭的时间尽量早。
假设THU ACM小组在时刻0到达十食堂,而且食堂里面没有其他吃饭的同学(只有打饭的师傅)。每个人必须而且只能被分在一个队伍里。两个窗口是并行操作互不影响的,而且每个人打饭的时间是和窗口无关的,打完饭之后立刻就开始吃饭,中间没有延迟。
现在给定N个人各自的打饭时间和吃饭时间,要求输出最佳方案下所有人吃完饭的时刻。
输入
第一行一个整数N,代表总共有N个人。 以下N行,每行两个整数 Ai,Bi。依次代表第i个人的打饭时间和吃饭时间。
输出
一个整数T,代表所有人吃完饭的最早时刻。
提示
所有输入数据均为不超过200的正整数。
样例说明 方案如下: 窗口1: 窗口2: 7 7 1 3 6 4 8 5 2 2
标签
dp[i][j][k]=min(dp[i][j][k],max(dp[i-1][j-e[i].a][k],j+e[i].b)); //这是第一个窗口 dp[i][j][k]=min(dp[i][j][k],max(dp[i-1][j][k-e[i].a],k+e[i].b)); //第二个
为什么我们要max,因为我们记录最大值,这个人排在这里可能比原来要长,取min不说了
但这个时候我们看一下会发现空间爆炸了怎么办???????借鉴我之前的dp经验肯定是要压一波空间了
滚动数组+1,如果你滚掉第一维理论上可以,但是 j , k 都是4e4级别的,舍掉
只能滚掉 j 或者 k ,假设滚掉第二个窗口 k ,接着就会发现那个k+e[i].b怎么办????
仔细看下其实发现 j + k 是前 i 个人排队时间的前缀和,高高兴兴滚掉
然后为什么可以正序,因为i由i-1滚过来,不会重叠
over!
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define N 1004 6 using namespace std; 7 struct node{ 8 int a,b; 9 }e[N]; 10 bool cmp(node a,node b){ 11 return a.b>b.b; 12 } 13 int sum[N]; 14 int f[205][40005]; 15 int main(){ 16 int n; 17 cin>>n; 18 for(int i=1;i<=n;i++) 19 cin>>e[i].a>>e[i].b; 20 sort(e+1,e+n+1,cmp); 21 for(int i=1;i<=n;i++) 22 sum[i]=sum[i-1]+e[i].a; 23 memset(f,0x3f3f3f3f,sizeof f); 24 f[0][0]=0; 25 for(int i=1;i<=n;i++){ 26 for(int j=0;j<=sum[i];j++){ 27 if(j>=e[i].a)f[i][j]=min(f[i][j],max(f[i-1][j-e[i].a],j+e[i].b)); 28 f[i][j]=min(f[i][j],max(f[i-1][j],sum[i]-j+e[i].b)); 29 } 30 } 31 int ans=2147483647; 32 for(int i=0;i<=sum[n];i++) 33 ans=min(ans,f[n][i]); 34 cout<<ans; 35 return 0; 36 }
额,还要补前面的题解,慢慢来