题意
n个人,每个人有打饭时间和吃饭时间,有两个打饭队列,求最后一个人吃完饭的时间最小值。
n,吃饭时间,打饭时间 <= 200
题解
发现数据范围小,可以想到n^3算法。
首先对于一个队列,内部顺序一定是吃饭吃的慢的放在前面。所以先按b从大到小排序。
设f[i][j]表示前i个人,1号队列总打饭时间为j时的 最慢的人吃完的时间。答案就是f[n][j]的最小值。
设a为打饭时间,b为吃饭时间,转移显然:
- f[i][j+b[i]]=min(f[i][j+b[i]],max(f[i-1][j],j+a[i]+b[i]))
- f[i][j]=max(f[i-1][j],suma[i-1]-j+a[i]+b[i])
因为求出a的前缀和,知道1号队列打饭时间,就知道2号队列打饭时间。
再加上滚动。
有点模拟思想的DP。
CODE
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 205;
struct node {
int a, b;
inline bool operator <(const node &o)const {
return b > o.b;
}
}p[MAXN];
int n, dp[MAXN*MAXN];
int main () {
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d%d", &p[i].a, &p[i].b);
sort(p + 1, p + n + 1);
memset(dp, 0x3f, sizeof dp);
dp[0] = 0; int sum = 0;
for(int i = 1; i <= n; ++i) {
for(int j = sum; j >= 0; --j) {
dp[j + p[i].a] = min(dp[j + p[i].a], max(dp[j], j + p[i].a + p[i].b));
dp[j] = max(dp[j], sum - j + p[i].a + p[i].b);
}
sum += p[i].a;
}
int ans = 1000000000;
for(int j = 0; j <= sum; ++j)
ans = min(ans, dp[j]);
printf("%d
", ans);
}