题意:
- 有一群人,每个人有一个打饭时间和一个吃饭时间。现在有两个窗口可以打饭,求让所有人吃完饭的最少时间。
思路:
首先想到贪心,在同一队里吃饭时间长的一定排在吃饭时间短的前面
(证明略)然后DP, 表示前i个人打完饭,第一队用时j的最小吃完饭时间(第二队用时可以用前 个人总时间减去 )。转移就比较方便了,可以选择把 放在第一队或者第二队。
DP最难的还是表示状态,我最开始一直在想 表示i个人在第一队j个人在第二队的情况下,两队的最小打饭时间,再有一个 记吃完饭时间。然而这样无法避免后效性
(状态转移都不行)贴个代码,以后还得多多练习:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 210;
int n, sum[N];
struct NODE{
int x, y;
}a[N];
int f[N][N*N];
bool cmp(NODE x, NODE y)
{
return x.y > y.y;
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i].x >> a[i].y;
sort(a+1, a+n+1, cmp);
sum[1] = a[1].x;
for (int i = 2; i <= n; i++)
sum[i] = sum[i-1]+a[i].x;
memset(f, 0x7f, sizeof(f));
f[0][0] = 0;
for (int i = 1; i <= n; i++)
for (int j = 0; j <= sum[i]; j++){
int k = sum[i]-j;
if (j >= a[i].x) f[i][j] = min(f[i][j], max(f[i-1][j-a[i].x], j+a[i].y));
if (k >= a[i].x) f[i][j] = min(f[i][j], max(f[i-1][j], k+a[i].y));
}
int ans = 0x7f7f7f7f;
for (int i = 0; i <= sum[n]; i++)
ans = min(f[n][i], ans);
cout << ans;
return 0;
}