洛谷1156 垃圾陷阱

题目: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;
}

猜你喜欢

转载自blog.csdn.net/scutbenson/article/details/82051896
今日推荐