zoukankan      html  css  js  c++  java
  • 【洛谷1156】垃圾陷阱(动态规划)

    点此看题面

    大致题意: 一只奶牛掉进了一个垃圾陷阱里,每个垃圾有三个属性:被扔下来的时间(T_i),吃了能够延长的生命时间(F_i),叠起来的高度(H_i)。每一个垃圾可以用来吃或叠,如果某一时刻垃圾叠起来的总高度大于等于(M),奶牛就可以离开这个陷阱。已知奶牛一开始能够存活10个单位时间,问你它离开陷阱最少所需的时间。如果它无论如何都无法离开陷阱,就输出它最多能够存活的时间。

    第一种情况:求离开陷阱最少所需的时间

    这题应该比较显然是一道(DP)题。

    首先要注意先将垃圾按照扔下来的时间(T_i)排序。

    我们可以用(f_{i,j})表示当前扔下了第(i)个垃圾,叠起来的总高度为(j)时还能存活的最大单位时间。

    我们可以用(f_{x,y}=-1)来表示这种情况不存在。

    那么依据题意,初始化时(f_{0,0}=10,f_{0,1...M}=-1).

    由于一个垃圾有两种用途,因此我们可以分类讨论第(i-1)个垃圾的用途:

    • 吃:(f_{i,j}=f_{i-1,j}+F_{i-1}-(T_i-T_{i-1}))
    • 叠:(f_{i,j}=f_{i-1,j-H_{i-1}}-(T_i-T_{i-1}))

    整理一下,就可以得出转移方程:$$f_{i,j}=max(f_{i-1,j}+F_{i-1},f_{i-1,j-H_{i-1}})-(T_i-T_{i-1})$$

    不难发现,若(f_{i,j}≠-1)(j+H_i≥M),就可以直接输出(T_i)并结束程序了。
    这就是针对第一种情况的解法。

    第二种情况:求最多能够存活的时间

    第二种情况的解法是建立在第一种情况的(DP)的基础之上的。

    可以看出,如果(f_{i,j})不为0,那么奶牛还能活的时间最大为(f_{i,j}+F_i)(吃掉当前的垃圾),那么总共能活的时间就是(f_{i,j}+T_i+F_i)

    不难发现,只要(f_{i,0}+T_i+F_i)不为(-1),它肯定大于(f_{i,x}+T_i+F_i(0<x≤M))(f_{y,0}+T_y+F_y(0≤y<i))的,因此,我们只要求出最大的满足(f_{i,0}≠-1)(i),答案就是此时的(f_{i,0}+T_i+F_i)

    代码

    #include<bits/stdc++.h>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define abs(x) ((x)<0?-(x):(x))
    #define LL long long
    #define ull unsigned long long
    #define swap(x,y) (x^=y,y^=x,x^=y)
    #define tc() (A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++)
    #define pc(ch) (pp_<100000?pp[pp_++]=(ch):(fwrite(pp,1,100000,stdout),pp[(pp_=0)++]=(ch)))
    #define N 100
    #define M 100
    int pp_=0;char ff[100000],*A=ff,*B=ff,pp[100000];
    using namespace std;
    int n,m,f[N+5][M+5];
    struct litter
    {
        int t,h,v;
    }a[N+5];
    inline void read(int &x)
    {
        x=0;int f=1;static char ch;
        while(!isdigit(ch=tc())) f=ch^'-'?1:-1;
        while(x=(x<<3)+(x<<1)+ch-48,isdigit(ch=tc()));
        x*=f;
    }
    inline void write(int x)
    {
        if(x<0) pc('-'),x=-x;
        if(x>9) write(x/10);
        pc(x%10+'0');
    }
    inline bool cmp(litter x,litter y)//将垃圾按照扔下来的时间排序
    {
        return x.t<y.t;
    }
    int main()
    {
        register int i,j,ans=0;
        for(read(m),read(n),i=1;i<=n;++i) read(a[i].t),read(a[i].v),read(a[i].h);
        for(f[0][0]=10,i=1;i<=m;++i) f[0][i]=-1;//初始化
        for(sort(a+1,a+n+1,cmp),i=1;i<=n;++i)//DP的核心代码
        {
            for(j=0;j<=m;++j)
            {
                if((f[i-1][j]<0||f[i-1][j]+a[i-1].v<a[i].t-a[i-1].t)&&((j>=a[i-1].h?f[i-1][j-a[i-1].h]:-1)<a[i].t-a[i-1].t)) {f[i][j]=-1;continue;}//如果当前状态无法转移到,就将f[i][j]赋值为-1,并跳过
                if(j+a[i].h>=m) return write(a[i].t),fwrite(pp,1,pp_,stdout),0;//如果将当前垃圾叠起来的总高度大于m,就输出当前垃圾被扔下来的时间并退出程序
                f[i][j]=max((j>=a[i-1].h?f[i-1][j-a[i-1].h]:-1),(f[i-1][j]>=0?f[i-1][j]+a[i-1].v:0))-(a[i].t-a[i-1].t);//求出f[i][j]
            }
        }
        for(i=1;i<=n;++i) if(~f[i][0]) ans=f[i][0]+a[i].t+a[i].v;else break;//求出最大的满足f[i][0]≠-1的i,答案就是此时的f[i][0]+T[i]+F[i]
        return write(ans),fwrite(pp,1,pp_,stdout),0;
    }
    
  • 相关阅读:
    苦逼也聊模式--(0)--开篇
    发现无力吐槽
    JS函数调用
    初步使用nodejs(一)
    测试一下
    达摩流浪者
    Revit:二开使用Sqlite保存本地数据,并配合EF6等ORM框架
    Revity:查找并修改类型参数和实例参数
    复习一下UML
    Revit:ElementFilter过滤器基类
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu1156.html
Copyright © 2011-2022 走看看