动态规划训练之一

动态规划专题一

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;
}
posted @ 2019-10-04 16:32  wzx_believer  阅读(128)  评论(0编辑  收藏  举报