能量石


題目描述

岩石怪物杜達生活在魔法森林中,他在午餐時收集了 NN 塊能量石准備開吃。

由於他的嘴很小,所以一次只能吃一塊能量石。

能量石很硬,吃完需要花不少時間。

吃完第 \(i\) 塊能量石需要花費的時間為 \(S_i\) 秒。

杜達靠吃能量石來獲取能量。

不同的能量石包含的能量可能不同。

此外,能量石會隨着時間流逝逐漸失去能量。

\(i\) 塊能量石最初包含 \(E_i\) 單位的能量,並且每秒將失去 \(L_i\) 單位的能量。

當杜達開始吃一塊能量石時,他就會立即獲得該能量石所含的全部能量(無論實際吃完該石頭需要多少時間)。

能量石中包含的能量最多降低至 0。

請問杜達通過吃能量石可以獲得的最大能量是多少?

范圍

\(1≤T≤10\)
\(1≤N≤100\)
\(1≤S_i≤100\)
\(1≤E_i≤10^5\)
\(0≤L_i≤10^5\)

題解

本題難點在於如何選擇能量石的順序。

假設我們能量石的最優序列為\(a_1,a_2,...,a_k\)

那么,交換第\(i\)和第\(j\)個可得:

\(E_i + (E_j - L_j \times S_i) \leq E_j + (E_i - L_i \times S_j)\)

化簡得:

\(S_i \times L_j \leq S_j \times L_i\)

這樣我們就得到了排序方式,可知最優解一定按這樣的順序出現。

之后就轉化為01背包問題,設\(f_t\)表示用了\(t\)時間能獲得的最大能量,計算即可.

代碼

#include <bits/stdc++.h>
using namespace std;
const int N = 110;
const int S = 10010;

struct node {
	int S,L;
	int E;
}s[N];
bool cmp(node a,node b) {
	return a.S * b.L <= a.L * b.S;
}
int f[S];
int t;
int T,n;
int cas;
int main () {
	cin >> T;
	while(T --) {
		cin >> n;
		t = 0;
		memset(f,-0x3f,sizeof f);
		for(int i = 1;i <= n; ++i) {
			cin >> s[i].S >> s[i].E >> s[i].L;
			t += s[i].S;
		}
		sort(s + 1,s + n + 1,cmp);
		f[0] = 0;
		for(int i = 1;i <= n; ++i) {
			for(int j = t;j >= s[i].S; --j) {
				f[j] = max(f[j],f[j - s[i].S] + max(0,s[i].E - (j - s[i].S) * s[i].L));
			}
		}
		int res = 0;
		for(int i = 1;i <= t; ++i) res = max(res,f[i]);
		printf("Case #%d: %d\n",++cas,res);
	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM