zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    关于windows客户端网络编程 WSAAsyncSelect函数
    阻塞模式和非阻塞模式
    SRP6协议分析
    普通二叉树转换成二叉查找树方法
    使用openssl库进行开发
    类型转化,网络开发中常见的类型转化
    到底还能够称多久
    权限子系统小结
    使用ASP.NET AJAX开发服务器端事件通知器
    通用权限相关文档的下载
  • 原文地址:https://www.cnblogs.com/bxd123/p/10617341.html
Copyright © 2011-2022 走看看