DP或者说是递推。
首先我们考虑一定要让吃饭慢的人排在前面,因为打饭的时间其实是固定的,所以首先要考虑吃饭慢的人先吃饭。然后再考虑两个窗口的问题。设置(dp[i][j])为前i个人在1号窗口打饭时间为j时,所用的最小的结束时间。只需知道前i个人的打饭时间,即可推出前i个人在2号窗口打饭的时间。
然后(DP),有转移方程:
(dp[i][j]=max(dp[i][j], sum[i]-j+data[i].b))这是最基础的式子,当前结束时间必是在1号窗口所使用的时间和在二号窗口中使用的时间中的最大值。
(dp[i][j]=MIN{max(dp[i-1][j-data[i].a],j+data[i].b)})当前的最小结束时间肯定不会比j+data[i].b小,也不会比前一个人的结束时间快,因此需要取他们的最大值,然后更新他们的最短结束时间取最小值。
#include <bits/stdc++.h>
#define N 100101
using namespace std;
int n, ans = 2147483647, dp[N], sum[N];//dp[i][j]表示第i个人在1号窗口打饭时间为j时,所用的最小的结束时间,可以压维,
struct dat {int a, b;}data[300];
bool cmp(dat a, dat b){return b.b < a.b;}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d", &data[i].a, &data[i].b);
sort(data + 1, data + 1 + n, cmp);//让吃饭时间长的人排在前面,简单的贪心
memset(dp, 123, sizeof(dp));//dp都设为最大值。
for (int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + data[i].a;//首先找所有人的打饭时间。
dp[0] = 0;
for (int i = 1; i <= n; i++)
for (int j = sum[i]; j; j--)//倒着枚举,可以压维。
{
if (j >= data[i].a)
dp[j] = min(dp[j], max(dp[j - data[i].a], j + data[i].b));//当前最小的结束时间一定等于当前两个窗口结束时间的最大值的最小值。
dp[j] = max(dp[j], sum[i] - j + data[i].b);
}
for (int i = 1; i <= sum[n]; i++)
ans = min(ans, dp[i]);
printf("%d", ans);
return 0;
}