洛谷P1156 Solution

题目链接

题解

⭐:试图达到或超过某目标值的dp可以考虑背包。

将高度视作体积,吃掉所延长的生命时间视作价值,井高视作背包容量,此题即可转化为一个类背包问题。因为我们是依时间由小到大的顺序对垃圾进行决策的,因此所找到的第一个可以达到井高的垃圾,其时间一定为最短时间。

状态:\(dp[i]\)表示当前垃圾高度为\(i\)时的最大生命时间。

初始值:\(dp[0]=10\)

转移方程:\(dp[j+h_i]=max(dp[j+h_i],dp[j]),\quad dp[j]+=f_i\quad (1\le i\le g,d\ge j\ge 0)\)

第一种情况为用垃圾\(i\)垫高,第二种为吃掉。如果\(j\)正序循环会导致取\(dp[j]\)\(dp[j+h_i]\)在后面循环中又\(+f_i\),也就是我们既用\(j\)垫高又将其吃掉,因此需倒序循环(也可以不将数组滚动)。

目标状态(如果无法出井):\(dp[0]\),因为不垫高并将能吃的都吃掉存活时间最长。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=110;
struct node {int t,f,h;} a[N];
int dp[N];
bool cmp(node x,node y) {return x.t<y.t;}
int main()
{
	int d,g;
	scanf("%d%d",&d,&g);
	for(int i=1;i<=g;i++) scanf("%d%d%d",&a[i].t,&a[i].f,&a[i].h);
	sort(a+1,a+g+1,cmp); dp[0]=10;
	for(int i=1;i<=g;i++)
	{
		for(int j=d;j>=0;j--)
		{
			if(dp[j]<a[i].t) continue;
			if(j+a[i].h>=d) {printf("%d",a[i].t); return 0;}
			dp[j+a[i].h]=max(dp[j+a[i].h],dp[j]);//垫高高
			dp[j]+=a[i].f;//吃掉 
		}
	}
	printf("%d",dp[0]);
	return 0;
}
原文地址:https://www.cnblogs.com/violetholmes/p/14540432.html