午餐题解
午餐题解
贪心+dp
1.贪心:
不妨取任意两人i,j,则:
打饭时间为:
\(\sum_{k=1}^{i-1}a_{k}+a_{i}+b_{i},\)
\(\sum_{k=1}^{i-1}a_{k}+a_{i}+\sum_{k=i+1}^{j-1}a_{k}+a_{j}+b_{j}\)
互换后打饭时间为:
\(\sum_{k=1}^{i-1}a_{k}+a_{j}+b_{j},\)
\(\sum_{k=1}^{i-1}a_{k}+a_{j}+\sum_{k=i+1}^{j-1}a_{k}+a_{i}+b_{i}\)
显然:\(\sum_{k=1}^{i-1}a_{k}+a_{j}+\sum_{k=i+1}^{j-1}a_{k}+a_{i}+b_{i}>\sum_{k=1}^{i-1}a_{k}+a_{i}+b_{i},\)
\(\sum_{k=1}^{i-1}a_{k}+a_{i}+\sum_{k=i+1}^{j-1}a_{k}+a_{j}+b_{j}>\sum_{k=1}^{i-1}a_{k}+a_{j}+b_{j},\)
则:比较
\(max(\sum_{k=1}^{i-1}a_{k}+a_{i}+b_{i},\sum_{k=1}^{i-1}a_{k}+a_{i}+\sum_{k=i+1}^{j-1}a_{k}+a_{j}+b_{j})\)和\(max(\sum_{k=1}^{i-1}a_{k}+a_{j}+b_{j},\sum_{k=1}^{i-1}a_{k}+a_{j}+\sum_{k=i+1}^{j-1}a_{k}+a_{i}+b_{i})\)
即为比较:
\(\sum_{k=1}^{i-1}a_{k}+a_{i}+\sum_{k=i+1}^{j-1}a_{k}+a_{j}+b_{j}\)
和\(\sum_{k=1}^{i-1}a_{k}+a_{j}+\sum_{k=i+1}^{j-1}a_{k}+a_{i}+b_{i}\)
两者之间只有\(b\)不同,故在越后面,b应越小,
将含\(a,b\)的结构体按\(b\)从大到小排序。
2.dp:
设数组\(f[i][j]\)表示到了第i个人,在第一窗口花了j时间的最小的最长时间:
for(int i=1;i<=n;++i){
sum+=x[i].a;
for(int j=0;j<=sum;++j){
f[i][j]=max(f[i-1][j],sum-j+x[i].b);
//若第二个人选择二号窗口,一号窗口的最长时间为f[i-1][j],之后第二窗口的最长时间为:sum-j+x[i].b(等到第i个人的时间总和不变)
if(j>=x[i].a) f[i][j]=min(f[i][j],max(j+x[i].b,f[i-1][j-x[i].a]));
//选一号窗口,第i个人的花费时间为j+x[i].b,前i-1个人花费的最长时间为f[i-1][j-x[i].a]
}
}
总代码:
#include<bits/stdc++.h>
using namespace std;
const int N=206;
int n,f[N][N*N+N],sum=0,ans=1e9;
struct xd{int a,b;}x[N];
inline int read(){
int T=0,F=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
return F*T;
}
bool cmp(xd u,xd v){return u.b>v.b;}
int main(){
n=read();
for(int i=1;i<=n;++i) x[i].a=read(),x[i].b=read();
sort(x+1,x+n+1,cmp),memset(f,0x7f,sizeof(f));
f[0][0]=0;
for(int i=1;i<=n;++i){
sum+=x[i].a;
for(int j=0;j<=sum;++j){
f[i][j]=max(f[i-1][j],sum-j+x[i].b);
if(j>=x[i].a) f[i][j]=min(f[i][j],max(j+x[i].b,f[i-1][j-x[i].a]));
}
}
for(int i=0;i<=sum;++i) ans=min(ans,f[n][i]);
printf("%d\n",ans);
return 0;
}