zoukankan      html  css  js  c++  java
  • 动态规划训练之一

    动态规划专题一

    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;
    }
    
  • 相关阅读:
    Android-setDefaultKeyMode方法
    Andorid-Fragment生命周期
    X210(s5pv210)中断系统
    X210串口配置与stdio移植
    SoC时钟系统简介
    SDRAM初始化
    重定位与链接脚本
    裸机配置C语言运行环境
    ARM汇编程序闪烁灯与其反汇编代码比较
    Makefile的简单使用
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/11622442.html
Copyright © 2011-2022 走看看