P1156 垃圾陷阱 DP

  

题目描述

卡门――农夫约翰极其珍视的一条Holsteins奶牛――已经落了到“垃圾井”中。“垃圾井”是农夫们扔垃圾的地方,它的深度为D(2 le D le 100)D(2D100)英尺。

卡门想把垃圾堆起来,等到堆得与井同样高时,她就能逃出井外了。另外,卡门可以通过吃一些垃圾来维持自己的生命。

每个垃圾都可以用来吃或堆放,并且堆放垃圾不用花费卡门的时间。

假设卡门预先知道了每个垃圾扔下的时间t(0< t le 1000)t(0<t1000),以及每个垃圾堆放的高度h(1 le h le 25h(1h25)和吃进该垃圾能维持生命的时间f(1 le f le 30)f(1f30),要求出卡门最早能逃出井外的时间,假设卡门当前体内有足够持续1010小时的能量,如果卡门1010小时内没有进食,卡门就将饿死。

输入输出格式

输入格式:

第一行为22个整数,DD和 G (1 le G le 100)G(1G100),GG为被投入井的垃圾的数量。

第二到第G+1G+1行每行包括33个整数:T (0 < T <= 1000)T(0<T<=1000),表示垃圾被投进井中的时间;F (1 le F le 30)F(1F30),表示该垃圾能维持卡门生命的时间;和 H (1 le H le 25)H(1H25),该垃圾能垫高的高度。

输出格式:

如果卡门可以爬出陷阱,输出一个整表示最早什么时候可以爬出;否则输出卡门最长可以存活多长时间。

输入输出样例

输入样例#1: 复制
20 4
5 4 9
9 3 2
12 6 10
13 1 1
输出样例#1: 复制
13

说明

[样例说明]

卡门堆放她收到的第一个垃圾:height=9height=9;

卡门吃掉她收到的第22个垃圾,使她的生命从1010小时延伸到1313小时;

卡门堆放第33个垃圾,height=19height=19;

卡门堆放第44个垃圾,height=20height=20。

dp不出来  参考了大佬的做法!!!!!!!!!!!

一共有四种状态: 物品  时间  生命 高度    其中物品和时间是联通的(物品要按照时间顺序排好)   所有只有三个变量

可以写二维的  也可以写成一维的滚动数组

其中这两种对时间的表达方式也有所不同

#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);i--)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define LL long long
#define pb push_back
#define fi first
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
///////////////////////////////////
#define inf 0x3f3f3f3f
#define N 300+5
struct node
{
    int life,high;
    int t;

}s[N];
int f[N];//前i个物品 j高度的最大血量

bool cmp(node a,node b)
{
    return a.t<b.t;
}

int main()
{
    int d,n;
    RII(d,n);
    rep(i,1,n)
    {
        RIII(s[i].t,s[i].life,s[i].high);
    }
    f[0]=10;
    sort(s+1,s+1+n,cmp);
    rep(i,1,n)
    repp(j,d,0)
        if(f[j]>=s[i].t)
        {
            if(j+s[i].high>=d)
            {
                cout<<s[i].t;
                return 0;
            }
            f[j+s[i].high]=max(f[j+s[i].high],f[j]);
            f[j]+=s[i].life;
        }
    cout<<f[0];
  return 0;

}
View Code

先尝试dp[i][j]dp[i][j]代表前i件物品处理后在j血量时达到的最大高度。

值得一提的是,j血量表示奶牛在暂时不考虑时间时所得到的最大血量

试着写一下它的状态转移方程

dp[i][j]=max(dp[i-1][j]+trash[i].h,dp[i-1][j+trash[i].c])dp[i][j]=max(dp[i1][j]+trash[i].h,dp[i1][j+trash[i].c])

发现这是对的,然而我们再想想,在关于j的一重循环里面,对j的取值我们似乎并不好判断,甚至要枚举很大。

所以我们再尝试讨论dp[i][j]dp[i][j]代表前i件物品处理后在h高度时达到的最大血量。

状态转移

dp[i][j]=max(dp[i-1][j]+trash[i].c,dp[i-1][j-trash[i].h])dp[i][j]=max(dp[i1][j]+trash[i].c,dp[i1][jtrash[i].h])

发现这样也是对的,而且j枚举起来也比较方便,于是我们选择这种算法。

总之因为高度比血量更小  所以枚举高度

#include <stdio.h>
#include <algorithm>
using namespace std;
#define maxn 1001
#define INF 0x7f7f7f7f
#define max(x,y) x>y?x:y
int f[101][1001];
struct arr
{
    int x,t,h;
}a[maxn];
int cmp(arr a,arr b)
{
    return a.x<b.x;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a[i].x,&a[i].t,&a[i].h);
    }
    sort(a+1,a+m+1,cmp);
    for (int i=0;i<=m;i++)
        for (int j=0;j<=n;j++)
            f[i][j]=-INF;
    f[0][0]=10; a[0].x=a[0].t=a[0].h=0;
    int fl=0;
    for (int i=1;i<=m;i++)
    {
        for (int j=0;j<=n;j++)
        {

            if (f[i-1][j]-a[i].x+a[i-1].x>=0) 
            {
                f[i][j]=max(f[i][j],f[i-1][j]-a[i].x+a[i-1].x+a[i].t);
            }
            if (f[i-1][j-a[i].h]-a[i].x+a[i-1].x>=0&&j-a[i].h>=0) 
            {
                f[i][j]=max(f[i][j],f[i-1][j-a[i].h]-a[i].x+a[i-1].x);
                if (j==n)
                {
                    printf("%d
",a[i].x);
                    fl=1;
                    return 0;
                }
            }
        }
    }
    int ans=0;
    if (!fl)
    {
        for (int i=0;i<=m;i++)
            for (int j=0;j<=n;j++)
                if (f[i][j]!=INF)
                ans=max(ans,f[i][j]+a[i].x);
        printf("%d
",ans);
    }
}
View Code
原文地址:https://www.cnblogs.com/bxd123/p/10617341.html