现在假设有两个相邻的人 a a a和 b b b,他们的打饭时间分别是 b u y [ a ] buy[a] buy[a]、 b u y [ b ] buy[b] buy[b],吃饭时间分别是 e a t [ a ] eat[a] eat[a]、 e a t [ b ] eat[b] eat[b]。
很容易发现不管哪个放在前面,所有人都打完饭的时间都是确定的。
如果把 a a a放在前面,那么所有人吃完饭的时间是
所有人打完饭的时间 + m a x ( e a t [ b ] , e a t [ a ] − b u y [ b ] ) max(eat[b],eat[a] - buy[b]) max(eat[b],eat[a]−buy[b])
如果把 b b b放在前面,则为
所有人打完饭的时间 + m a x ( e a t [ a ] , e a t [ b ] − b u y [ a ] ) max(eat[a],eat[b] - buy[a]) max(eat[a],eat[b]−buy[a])
如果把 a a a放在前面更优,那么我们可以得到以下的不等式:
m a x ( e a t [ b ] , e a t [ a ] − b u y [ b ] ) < m a x ( e a t [ a ] , e a t [ b ] − b u y [ a ] ) max(eat[b],eat[a] - buy[b]) < max(eat[a],eat[b] - buy[a]) max(eat[b],eat[a]−buy[b])<max(eat[a],eat[b]−buy[a])
然后我还是不会解啊!
难道要分类讨论吗?
**不等式成立的充要条件就是,不等号右边的两个式子里面,至少有一个既大于左边的第一个式子,又大于左边的第二个式子:
**要么
$ eat[a] > eat[b] ~~~ $ && $ ~~~ eat[a] > eat[a] - buy[b]$
要么
$eat[b]-buy[a] > eat[b] ~~~ $ && $ ~~~ eat[b] - buy[a] > eat[a] - buy[b]$
( e a t [ b ] − b u y [ a ] > e a t [ b ] eat[b]-buy[a] > eat[b] eat[b]−buy[a]>eat[b]永远不可能成立,舍去)
所以说只有当上面的一组不等式成立时 a a a才应该放在前面,化简也就是 e a t [ a ] > e a t [ b ] eat[a] > eat[b] eat[a]>eat[b]。
由于两个队伍最后的结构都会遵循eat值递减的规律,所以可以先对所有人按eat值递减排序,再为他分配队伍。
其实也可以看做是一个背包,从 n n n个人中选择部分人,使得最后的指标--------所有人的时间最短。
最基本的思路就是令 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示考虑到第 i i i 个人,A队目前排队时间 j j j 分钟,B队目前排队 k k k 分钟时,所有人吃完饭所需要的时间。
为什么可以这样做?因为对于一个将要新加入队伍的人来讲,前面的人吃饭的时间不会因为他的加入而变化,他加入哪个队伍后只可能是因为他自己吃饭太慢而拖后腿,所以我们判断一下他会不会拖后腿,如果拖了后腿更新答案就可以了。
但是这样内存会不够,所以我们需要进行空间上的优化。
就如上面所说,当考虑到第 i i i个人时,所有人的打饭时间是一定的。
如果我们用一个前缀和 s u m [ i ] sum[i] sum[i] 记录前 i i i 个人打完饭一共需要多长时间,那么有 j + k = = s u m [ i ] j + k == sum[i] j+k==sum[i] , 就是说如果我知道A队的人排队需要多久,那么前缀和减去他们等待的时间就是B队需要等待的时间。
~~~~
我们首先考虑把新人加入A队:
这时候有三种可能性:
把新人加入B队的情况类似。
#include
#include
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a
using namespace std;
const int INF = 1e9;
int n;
int buy[205];
int eat[205];
int sum[205];
int ord[205];
int f[205][40005];
bool cmp(int x, int y){
return eat[x] > eat[y];
}
int main(){
cin >> n;
for(int i = 1; i <= n; i++){
cin >> buy[i] >> eat[i];
ord[i] = i;
}
sort(ord + 1, ord + 1 + n, cmp);
for(int i = 1; i <= n; i++)
sum[i] = sum[i-1] + buy[ord[i]];
for(int i = 1; i <= n; i++)
for(int j = 0; j <= sum[n]; j++)
f[i][j] = INF;
for(int i = 1; i <= n; i++){
int id = ord[i];
for(int j = 0; j <= sum[i-1]; j++){
if (f[i-1][j] == INF) continue;
int other = sum[i-1] - j;
//go to list1
int wait1 = max(j + buy[id] + eat[id], f[i-1][j]);
//go to list2
int wait2 = max(other + buy[id] + eat[id], f[i-1][j]);
f[i][j+buy[id]] = min(f[i][j+buy[id]], wait1);
f[i][j] = min(f[i][j], wait2);
}
}
int ans = INF;
for(int i = 0; i <= sum[n]; i++)
ans = min(ans, f[n][i]);
cout << ans << endl;
}