【codevs 1684】垃圾陷阱

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 
#include 
#include 
#include 
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 
#include 
#include 
#include 
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 
#include 
#include 
#include 
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;
}

你可能感兴趣的:(===动态规划===)