原题: https://www.luogu.org/problemnew/show/P2577
题意:
n个人打饭,每个人有给出的打饭时间和吃饭时间。两个窗口,排队打饭,问最少的时间使所有人吃完饭。
解析:
首先是贪心选排队顺序。
因为一个队的总时间为:所有人的打饭时间,加最后一个人的吃饭时间,加如果有前面吃饭吃得慢的人的吃饭时间。分析最优解,假设最优解两队人顺序都是吃饭慢的先排队,此时调换顺序,则可能会变慢,但绝对不会变快。所以贪心成立。
接下来是两队的分配。
可以想到的dp为dp[i][j][k]
表示:对于前i个人,第一队排队时间j,第二队排队时间k,此时的最优解(吃完饭)。为什么是排队时间?因为好实现,塞一个人进去直接加上他的排队时间,不用考虑吃饭的问题。
但是维度比较大,需要降维。这个也比较明显,因为前面i个人的总排队时间s知道了,k=s-j就省去一维了。
dp[i][j]
代表:对于前i个人,第一队排队时间j时的最优解。
对于第i个人,如果塞到第一队,那么首先考虑i-1个人的情况dp[i-1][j-a[i]]
,还有第i个人吃饭的时间j+b[i]
;
如果塞到第二队,那么第一队的情况为dp[i-1][j]
,第二队第i人吃饭的情况s[i]-j+b[i]
。
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
struct node{
int a,b;
bool operator <(const node &r)const{
return b>r.b;
}
} e[205];
int dp[205][205*205];
int s[205];
int main(){
memset(dp,0x3f,sizeof dp);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&e[i].a,&e[i].b);
}
sort(e+1,e+1+n);
for(int i=1;i<=n;i++)s[i]=e[i].a+s[i-1];
dp[0][0]=0;
for(int i=1;i<=n;i++){
for(int j=e[i].a;j<=s[i];j++){
dp[i][j]=min(dp[i][j],max(dp[i-1][j-e[i].a],j+e[i].b));
}
for(int j=0;j<=s[i];j++){
dp[i][j]=min(dp[i][j],max(dp[i-1][j],s[i]-j+e[i].b));
}
}
int ans=0x3f3f3f3f;
for(int i=0;i<=s[n];i++){
ans=min(ans,dp[n][i]);
}
printf("%d\n",ans);
}