题目:https://www.luogu.org/problemnew/show/P2577
题意:n个人每个人有一个打饭时间和吃饭时间,将他们分成两个队伍。每个人打到饭之后就马上去吃饭。问怎么安排可以让总体的吃饭时间最短。
思路:首先贪心还是很好想的。某个队伍的总吃饭时间实际上是打饭结束+吃饭时间最晚的那个时间。
一个队伍前面的那些人,如果他们吃完饭的时间都不超过总的排队时间的话,根本不需要考虑他们。而队伍的排队时间如果安排好了,是固定的。跟安排的顺序没有关系。
所以我们应该要把吃饭时间长的往前放。因为排队时间不受顺序影响但是吃饭时间受顺序的影响。
然后我们可以考虑怎么给他们分成两队。
首先可以考虑$dp[i][j][k]$表示考虑到第$i$个人,第一条队伍排队时间是$j$第二条队伍排队时间是$k$的时候,最早全部吃完饭的时间。
但是我们发现$j$和$k$存在关系,因为两个队伍总的排队时间是固定的。所以我们可以用$sum[i]$来维护排队时间的前缀和。就可以减少一个维度了。
所以我们可以用$dp[i][j]$表示考虑到第$i$个人,第一条队伍排队时间是$j$最早全部吃完饭的时间。此时显然第二条队伍的排队时间是$sum[i] - j$
于是有$dp[i][j] = min(max(dp[i-1][j-get[i]], j + eat[i]), max(dp[i - 1][j], sum[i] - j + eat[i]))$分别表示第$i$个人排在第一个队伍和排在第二个队伍。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<map> 4 #include<set> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<cmath> 9 #include<stack> 10 #include<queue> 11 #include<iostream> 12 13 #define inf 0x3f3f3f3f 14 using namespace std; 15 typedef long long LL; 16 typedef pair<int, int> pr; 17 18 int n; 19 const int maxn = 205; 20 struct node{ 21 int get, eat; 22 }stu[maxn]; 23 int sum[maxn]; 24 int dp[maxn][maxn * maxn * 2]; 25 26 bool cmp(node a, node b) 27 { 28 return a.eat > b.eat; 29 } 30 31 int main() 32 { 33 scanf("%d", &n); 34 memset(dp, 0x3f, sizeof(dp)); 35 for(int i = 1; i <= n; i++){ 36 scanf("%d%d", &stu[i].get, &stu[i].eat); 37 } 38 sort(stu + 1, stu + 1 + n, cmp); 39 40 for(int i = 1; i <= n; i++){ 41 sum[i] = sum[i - 1] + stu[i].get; 42 } 43 dp[0][0] = 0; 44 for(int i = 1; i <= n; i++){ 45 for(int j = 0; j <= sum[i]; j++){ 46 if(j >= stu[i].get)dp[i][j] = min(dp[i][j], max(dp[i - 1][j - stu[i].get], j + stu[i].eat)); 47 dp[i][j] = min(dp[i][j], max(dp[i - 1][j], sum[i] - j + stu[i].eat)); 48 } 49 } 50 51 int ans = inf; 52 for(int j = 0; j <= sum[n]; j++){ 53 ans = min(ans, dp[n][j]); 54 } 55 printf("%d\n", ans); 56 return 0; 57 }