1 条题解
-
0
自动搬运
来自洛谷,原作者为

M_seа
**搬运于
2025-08-24 21:39:16,当前版本为作者最后更新于2018-02-21 17:35:45,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
这道题目比较难想。
算法:贪心+dp
容易想到贪心:吃饭慢的先打饭节约时间, 所以先将人按吃饭时间从大到小排序。
然后就是dp了: 首先,应该想到f[i][j][k]:前i个人,在1号窗口打饭总时间j,在2号窗口打饭总时间k
当然,这样会爆空间,所以想到去掉一维。
f[i][j]表示前i个人,在1号窗口打饭总时间j,最早吃完饭的时间
我们可以发现 j+k=前i个人打饭总和,k = sum(i)-j。 所以可以维护一个前缀和:
for(int i = 1; i <= n; i++) sum[i] = sum[i-1] + s[i].a;接下来就是dp的转移:
将第i个人放在1号窗口: if(j>=s[i].a) f[i][j] = min(f[i][j], max(f[i-1][j-s[i].a], j+s[i].b)); f[i-1][j-s[i].a]是i号人打饭+吃饭的时间不足i-1号人吃饭的时间, 所以没有影响 j+s[i].b就是造成了影响 将第i个人放在2号窗口: f[i][j] = min(f[i][j], max(f[i-1][j], sum[i]-j+s[i].b)); 这里也是一样的 (sum[i]-j 就是k)转移方程如果没有看懂,可以结合图来理解
完整代码:
#include<bits/stdc++.h> using namespace std; const int N = 210; int f[N][N*N]; struct node { int a, b; bool operator <(node z) const { return b>z.b; } }s[N]; int sum[N]; int main() { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d %d", &s[i].a, &s[i].b); sort(s+1, s+1+n); for(int i = 1; i <= n; i++) sum[i] = sum[i-1] + s[i].a; memset(f, 127, sizeof(f)); f[0][0] = 0; for(int i = 1; i <= n; i++) { for(int j = 0; j <= sum[i]; j++) { if(j>=s[i].a) f[i][j] = min(f[i][j], max(f[i-1][j-s[i].a], j+s[i].b)); f[i][j] = min(f[i][j], max(f[i-1][j], sum[i]-j+s[i].b)); } } int ans = 2147483647; for(int i = 0; i <= sum[n]; i++) ans = min(ans, f[n][i]); printf("%d\n", ans); return 0; }
- 1
信息
- ID
- 1615
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者