題解:P1156 垃圾陷阱

Anins發表於2024-11-24

P1156 垃圾陷阱

思路:

很顯然這是一道動態規劃,且每個物品有兩種選擇:用作增加生命或高度。

增加高度會損失一定的生命,反之同理,是不是很像揹包問題?確實是它的變形。
考慮設 \(f[i][j]\) 表示到第 \(i\) 個物品,生命值為 \(j\) 時所到達的最大高度。
那麼我們考慮轉移,顯然對於物品 \(i\) 用作增加高度有:

\(f[i][j]=max(f[i-1][j]+h[i])\)

用作增加生命有:

\(f[i][j]=max(f[i-1][j-f[i]])\)

坑點:

  1. 注意轉移呼叫變數時奶牛是否還存活。

  2. 給出的垃圾掉落時間的 \(t\) 陣列不保證單調遞增,需要排序。

程式碼:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node {
	ll t, f, h, sum;
	bool operator < (node &a) {return t<a.t;}
}a[1005];
ll h, n;
ll f[105][100005]; //f[i][j]表示前i個垃圾生命值為j時能達到的最高高度 
int main() {
	cin >> h >> n;
	for(int i=1; i<=n; i++) cin >> a[i].t >> a[i].f >> a[i].h; //t表示投放時間,f表示增加的生命值,h表示墊高高度 
	sort(a+1, a+n+1); //注意給出的時間不遞增 
	a[0].sum=10;
	for(int i=1; i<=n; i++) a[i].sum=a[i-1].sum+a[i].f; //a[i].sum表示到i能達到的最大高度 
	memset(f, -0x3f, sizeof(f));
	f[0][10]=0; //初始化 
	for(int i=1; i<=n; i++) {
		if(a[i].t>a[i-1].sum) { //就算前面的所有垃圾都吃也堅持不到這個垃圾,輸出最大高度 
			cout << a[i-1].sum;
			exit(0);
		}
		for(int j=a[i].t; j<=a[i].sum; j++) { //j從a[i].t開始列舉保證能存活到當前垃圾投放,且最大高度不大於a[i].sum 
			f[i][j]=max(f[i][j], f[i-1][j]+a[i].h); //這個垃圾用來墊高高度 
			//接下來考慮這個垃圾用來增加生命值,那麼j-a[i].f>=0且j-a[i].f>=a[i].t(保證能活到當前垃圾時間)
			if(j-a[i].f>=0&&j-a[i].f>=a[i].t) f[i][j]=max(f[i][j], f[i-1][j-a[i].f]);
			if(f[i][j]>=h) { //如果不小於h說明到i時就出去了,輸出a[i].t
				cout << a[i].t;
				exit(0);
			}
		}
	}
	cout << a[n].sum; //能執行到這裡說明所有最大高度不足以出洞 
	return 0;
}

相關文章