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 的高度
转移?
但是要注意:只有能够活到这个时刻,你才能用这个时刻的物品
所以 记录生命值为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的情况是否可达
转移?
代码如下:
#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的最大存活时间
所以啊 方程不会搞的时候 可以把下标和存储内容换过来……
转移?
代码如下:
#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;
}