动态规划训练之一
动态规划专题一
https://www.luogu.org/problem/P2577
分析:
首先本题不是贪心排序就是dp
再数据范围<=200,就只有可能是dp了
考虑本题,容易想到应该尽量让那些打饭快却吃饭慢的排在前面
又因为所有人打饭的总时间是一定的,
即无论怎么安排所有人打完饭都会耗费这么多时间
所以我们只用考虑吃饭慢的排在前面则一定是最优的
但此时有两个窗口,怎样安排就要dp了
-
用f[i,j]记录前i个人排队,第一队用时为j的情况下最大用时。
-
不记录第2队状态的原因是可以由第一队状态推出来。
-
为了便于计算,建议使用前缀和维护一下,可以较为简易的计算出第2队的情况。
-
那么我们就得到了这样个方程:
加入第一队的情况下: f[i,j]=min(f[i,j],max(f[i-1,j-a[i].x],j+a[i].y));
当前最小时间为上一个人用的时间和这一个人用的时间的最大值
加入第二队同理
f[i,j]=max(f[i-1,j],a[i].y+b[i]-j)其中b[i]为前i个人排队所用的总时间
然而200*40000好像有点大,降维呗!
类似背包一样降维就行
code by std:
#include<bits/stdc++.h>
using namespace std;
struct lsg{int x,y;}a[1000];
int n,f[400001],sum,ans,b[1000];
bool pd(lsg x,lsg y){return x.y>y.y;}
int main(){
ios::sync_with_stdio(false);
cin>>n;
for (int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
sort(a+1,a+1+n,pd);memset(f,10,sizeof(f));f[0]=0;
for (int i=1;i<=n;i++)b[i]=a[i].x+b[i-1];
for (int i=1;i<=n;i++){
for (int j=sum;j>=0;j--){
f[j+a[i].x]=min(f[j+a[i].x],max(f[j],a[i].y+j+a[i].x));//将i加入第一个队列
f[j]=max(f[j],a[i].y+b[i]-j);//将i加入第二个队列
}
sum+=a[i].x;
}
ans=1e9;
for (int i=1;i<=sum;i++)ans=min(ans,f[i]);
cout<<ans<<endl;
}