【codevs 1684】垃圾陷阱

来源:互联网 发布:淘宝金丝绒裙子图片 编辑:程序博客网 时间:2024/05/19 13:09

1684 垃圾陷阱
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 黄金 Gold
题解
查看运行结果
题目描述 Description
卡门——农夫约翰极其珍视的一条Holsteins奶牛——已经落了到“垃圾井”中。“垃圾井”是农夫们扔垃圾的地方,它的深度为D (2 <= D <= 100)英尺。

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

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

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

输入描述 Input Description
第一行为2个整数,D 和 G (1 <= G <= 100),G为被投入井的垃圾的数量。

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

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

样例输入 Sample Input
20 4

5 4 9

9 3 2

12 6 10

13 1 1

样例输出 Sample Output
13

数据范围及提示 Data Size & Hint
[样例说明]

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

卡门吃掉她收到的第二个垃圾,使她的生命从10小时延伸到13小时;

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

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

成功get3种做法√

首先,对于每个物品,如果能够撑到它来,才能选择吃与垫//不然就只能去死了
其次,如果逃不掉,显然都吃掉,活的时间才是最久的

输入并不保证时间顺序,所以要自己按照出现时间排序

先想一个比较好想的做法

dp[i][j]表示到了第i个物品 时刻为j 的高度
转移?

dp[i][j]=dp[i1][j+l[i].f];
dp[i][j]=dp[i1][j]+l[i].h;

但是要注意:只有能够活到这个时刻,你才能用这个时刻的物品
所以 记录生命值为nowsm, nowsm < l[i].t,必死

代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN = 105;int D,G,nowsm = 10,dp[MAXN][25005];//第i个在j时刻的高度 /*    吃?生命 >= 当前时间     堆?能等到它 */ struct edge{    int t,f,h;}l[MAXN]; bool cmp(edge a,edge b){return a.t < b.t;}int main(){    memset(dp,0xff,sizeof(dp));    scanf("%d %d",&D,&G);    for(int i = 1; i <= G; i ++)         scanf("%d %d %d",&l[i].t,&l[i].f,&l[i].h);    sort(l + 1,l + G + 1,cmp);    for(int i = 0;i <= 10; i ++) dp[0][i] = 0;    for(int i = 1; i <= G; i ++){        if(nowsm < l[i].t) {printf("%d\n",nowsm); return 0;}         //如果当前生命值撑不到下一个 那我只能活到这时候了         nowsm += l[i].f;//撑得到就续上         for(int j = 0; j <= nowsm; j ++){//j是时刻              dp[i][j] = dp[i - 1][j];//先转移 吃掉了所以高度不变              if(j >= l[i].t){                 if(j - l[i].f >= l[i].t) //不吃这个辣鸡也可以活命                     dp[i][j] = max(dp[i][j],dp[i - 1][j - l[i].f] );//看看之前的状态有没有更优的                 if(dp[i - 1][j] != -1) //存在这个状态 即上一个垃圾就能活到现在                     dp[i][j] = max(dp[i][j],dp[i - 1][j] + l[i].h);//垫上 上一个转移保证这个的最优性                 if(dp[i][j] >= D) {printf("%d\n",l[i].t);return 0;}//能跑就跑             }        }    }    printf("%d\n",nowsm);//吃掉所有辣鸡 一个都不垫     return 0;}

通过这个可以衍生出一种做法

bool dp[i][j] , 记录高度为i 生命为j的情况是否可达
转移?

dp[i][j+l[k].f]]=true;
dp[i+l[j].h][k]=true;

逃不掉就记录能存活的最长时间//就是最大的j

代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int D,G,sum = 10,ans = 0;bool dp[5005][5005];/*  可行性 : 高度为i 生命为j 的情况是否存在     dp[i + l[j].h][k] = true;    dp[i][j + l[k].f] = true; */struct edge{    int t,f,h;}l[105];bool cmp(edge a,edge b){return a.t < b.t;}int main(){    memset(dp,0,sizeof(dp));    scanf("%d %d",&D,&G),dp[0][10] = true;    for(int i = 1; i <= G; i ++)         scanf("%d %d %d",&l[i].t,&l[i].f,&l[i].h),sum += l[i].f;    sort(l + 1,l + G + 1,cmp);    for(int i = 1; i <= G; i ++)        for(int j = D - 1; j >= 0; j --)//D-1            for(int k = sum; k >= l[i].t; k --){//之后的                 if(!dp[j][k]) continue;                 dp[j + l[i].h][k] = dp[j][k + l[i].f] = true;                if(j + l[i].h >= D){printf("%d\n",l[i].t);return 0;}            }    for(int i = 0; i < D; i ++)        for(int j = 10; j <= sum; j ++)            if(dp[i][j]) ans = max(ans,j);    printf("%d\n",ans);    return 0;   }

最后我们来看正解

正解只有一维!
dp[i] : 高度为i的最大存活时间

所以啊 方程不会搞的时候 可以把下标和存储内容换过来……

转移?

dp[i]=dp[j]+l[j].t;
dp[i]=dp[i+l[j].h];

代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN = 1005;int D,G,dp[MAXN];//高度为i的最大存活时间 /*    吃:dp[i] = dp[j] + l[j].t;    堆:dp[i] = dp[i + l[j].h]; */struct edge{    int t,f,h;}l[MAXN];bool cmp(edge a,edge b){return a.t < b.t;}int main(){    scanf("%d %d",&D,&G);    for(int i = 1; i <= G; i ++)        scanf("%d %d %d",&l[i].t,&l[i].f,&l[i].h);    sort(l + 1,l + 1 + G,cmp),dp[0] = 10;    for(int i = 1;i <= G; i ++)//i是第几个 j是高度         for(int j = D; j >= 0; j --){//大于等于0!可以不垫             if(dp[j] >= l[i].t){                if(j + l[i].h >= D) {printf("%d\n",l[i].t);return 0;}                   dp[j + l[i].h] = max(dp[j],dp[j + l[i].h]);//垫 存活时间是原来的时间                 dp[j] = dp[j] + l[i].f; //这个要放在后面 用来吃              }        }    printf("%d\n",dp[0]);    return 0;}
原创粉丝点击