【洛谷1156】垃圾陷阱(动态规划)

本文探讨了一只奶牛陷入垃圾陷阱的问题,使用动态规划解决如何以最短时间和最多存活时间离开陷阱。文章详细介绍了两种情况的解题思路,并提供了相应的状态转移方程。

点此看题面

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


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

这题应该比较显然是一道 D P DP DP题。

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

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

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

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

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

  • 吃: f i , j = f i − 1 , j + F i − 1 − ( T i − T i − 1 ) f_{i,j}=f_{i-1,j}+F_{i-1}-(T_i-T_{i-1}) fi,j=fi1,j+Fi1(TiTi1)
  • 叠: f i , j = f i − 1 , j − H i − 1 − ( T i − T i − 1 ) f_{i,j}=f_{i-1,j-H_{i-1}}-(T_i-T_{i-1}) fi,j=fi1,jHi1(TiTi1)

整理一下,就可以得出转移方程: f i , j = m a x ( f i − 1 , j + F i − 1 , 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}) fi,j=max(fi1,j+Fi1,fi1,jHi1)(TiTi1)

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


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

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

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

不难发现,只要 f i , 0 + T i + F i f_{i,0}+T_i+F_i fi,0+Ti+Fi不为 − 1 -1 1,它肯定大于 f i , x + T i + F i ( 0 &lt; x ≤ M ) f_{i,x}+T_i+F_i(0&lt;x≤M) fi,x+Ti+Fi(0<xM) f y , 0 + T y + F y ( 0 ≤ y &lt; i ) f_{y,0}+T_y+F_y(0≤y&lt;i) fy,0+Ty+Fy(0y<i)的,因此,我们只要求出最大的满足 f i , 0 ≠ − 1 f_{i,0}≠-1 fi,0̸=1 i i i,答案就是此时的 f i , 0 + T i + F i f_{i,0}+T_i+F_i fi,0+Ti+Fi


代码
#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值