题目:https://www.luogu.org/problemnew/show/P1156
思路:
其实这题很像01背包(我太弱了想了很久)
但又有点不同,这个深度d可以装满甚至溢出,即>=d
所以
我们可以把深度d看成背包大小
每个垃圾的高度看成物品重量
只剩物品的价值了
那就由垃圾回血量来看吧。。。
感觉怪怪的。。。那就变个型吧~
把当前的血量看成物品的价值咯
于是我(在看了题解的情况下)很快的写出了状态转移方程:
1,吃:dp[i,j]=max(dp[i-1,j]-时差+回血);
2,不吃:dp[i,j]=max(dp[i-1,j-高度]-时差);
于是。。。70分。。。
纳尼???!!!
(再看一眼题解后)
原来,我的dp数组的下标范围出了问题。。。
回到最开始
此题跟01背包的区别是可以溢出。。。即 j>=d
状态转移方程的下标最好定为题目给的数据范围
即j<=d 那么
1,吃:dp[i,j]=max(dp[i-1,j]-时差+回血);
2,不吃:dp[i,j+高度]=max(dp[i-1,j]-时差); 同时也少了个量。。。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct node
{
int t,h,s;
};
const int maxSize=100,maxValue=10000000;
int d,g;
int f[maxSize+5][25000+5],sum[maxSize+5];
//f[i][j] 前i个垃圾堆高度j的最大hp
//用j+a[i].h 原因:
//1,j为高度,可能 >d
//2,方便编写,不用太多特判
node a[maxSize+5];
void dp()
{
int i,j,ans=0;
for (i=0;i<=g;i++)
for (j=0;j<=d;j++)
f[i][j]=-maxValue;
f[0][0]=10;
for (i=1;i<=g;i++)
{
for (j=d;j>=0;j--)
{
if (f[i-1][j]<a[i].t-a[i-1].t)//不存在状态f[i-1,j] or 不能等到第i个垃圾就挂了
continue;
if (j+a[i].h>=d && f[i-1][j]>=0)//可以逃出
{
printf("%d\n",a[i].t);
return ;//游戏结束,直接return即可
}
f[i][j]=max(f[i][j],f[i-1][j]-(a[i].t-a[i-1].t)+a[i].s);
f[i][j+a[i].h]=max(f[i][j+a[i].h],f[i-1][j]-(a[i].t-a[i-1].t));
}
ans=max(ans,f[i][0]+a[i].t);//第i个垃圾掉下来的时间 + 马丁的hp=马丁最多能活多久
}
printf("%d\n",ans);
}
bool cmp(node x,node y)
{
return x.t<y.t;
}
int main()
{
int i;
freopen("a.txt","r",stdin);
scanf("%d%d",&d,&g);
sum[0]=0; a[0].t=0; a[0].s=0; a[0].h=0;
for (i=1;i<=g;i++)
scanf("%d%d%d",&a[i].t,&a[i].s,&a[i].h);
sort(a+1,a+g+1,cmp);
// for (i=1;i<=g;i++)
// sum[i]=sum[i-1]+a[i].h;
// for (i=1;i<=g;i++)printf("%d\n",a[i].t);
memset(f,0,sizeof(f));
dp();
return 0;
}