洛谷p1048 採藥

chrispang發表於2024-08-20

本題其實是一個 \(01\) 揹包的板子題,除了題目背景不同以外,其它的都一模一樣!

  • \(1\)、狀態:

定義一個二維陣列 f,\(f_{i\ j}\)表示前 \(i\) 種採藥,時間為 \(j\) 時可以獲得的最大價值。

  • \(2\)、狀態轉移方程:

我們設當前時間為 \(j\) 採完這個草藥需要的時間 \(t\),採摘這個草藥可以獲得的價值為 \(w\)。則分兩種情況:

\(1.\) 如果 \(j \ge t\),那麼可以選這個草藥,也可以不選:\(f_{i\ j} = max(f_{i-1\ j}, \ f_{i-1\ j-t}+w)\)
\(2.\) 那麼如果 \(j < t\),那麼不能選這個草藥:\(f_{i\ j} = f_{i-1\ j}\)

  • \(3\)、初始化

由於如果當前時間為 \(0\),那麼你是永遠也湊不出來一個值的,所以 \(f_{i\ 0} = 0\)

  • \(4\)、答案

我們最後要求時間為 \(T\) 時,求最大利益,那麼也就是 \(max(f_{i\ T})(1 \le i \le n)\)

程式碼:

#include <bits/stdc++.h>
using namespace std;

int T, m, ans, f[110][1010]; //f[i][j]表示前i種草藥時間為j時能採摘到達最大價值 
struct node {
	int t, w; //一個草藥需要花費時間和得到價值 
}a[110];

int main() {
	cin >> T >> m;
	for (int i = 1; i <= m; i++)
		cin >> a[i].t >> a[i].w;
	for (int i = 1; i <= m; i++)
		f[i][0] = 0; //初始化 
	for (int i = 1; i <= m; i++)
		for (int j = 1; j <= T; j++)
			if(j >= a[i].t) f[i][j] = max(f[i - 1][j], f[i - 1][j - a[i].t] + a[i].w); //如果時間充足,則需要考慮選或不選 
			else f[i][j] = f[i - 1][j]; //否則不選 
	for (int i = 1; i <= m; i++)
		ans = max(ans, f[i][T]); //找最佳答案 
	cout << ans << endl;
    return 0;
}