原題連結:https://www.luogu.com.cn/problem/P1802
題意解讀:x個藥取打n個怪,打贏打輸都有經驗,計算最大的經驗數,跟01揹包類似,可以理解為一個物品裝得下或者裝不下都可以裝,裝得下獲得的價值高,裝不下獲得的價值低。
解題思路:
設lose[N], win[N], use[N]表示失敗時獲得的經驗,勝利時獲得的經驗和打過要至少使用的藥數量;
設dp[i][j]表示用j個藥打前i個怪所能獲得的最大經驗;
當j >= use[i]時,可以選擇打贏或者打輸dp[i][j] = max(dp[i-1][j] + lose[i], dp[i-1][j-use[i]] + win[i]),注意打輸是dp[i-1][j] + lose[i],j優先用來打前i-1,剩下的再對i打輸,這樣才是最優;
當j < use[i]時,只能打輸,把藥優先打前i-1個怪,dp[i][j] = dp[i-1][j] + lose[i]。
100分程式碼(二維):
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n, x;
int lose[N], win[N], use[N];
int dp[N][N]; //dp[i][j]表示前i個人j個藥能獲得的最大經驗
int main()
{
cin >> n >> x;
for(int i = 1; i <= n; i++) cin >> lose[i] >> win[i] >> use[i];
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= x; j++)
{
dp[i][j] = dp[i-1][j] + lose[i]; //藥劑j不夠打i,只能打敗
if(j >= use[i]) dp[i][j] = max(dp[i][j], dp[i-1][j-use[i]] + win[i]); //藥劑j夠打i,可以打贏或者打輸
}
}
cout << 5ll * dp[n][x] << endl;
return 0;
}
100分程式碼(一維):
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n, x;
int lose[N], win[N], use[N];
int dp[N]; //dp[j]表示j個藥能獲得的最大經驗
int main()
{
cin >> n >> x;
for(int i = 1; i <= n; i++) cin >> lose[i] >> win[i] >> use[i];
for(int i = 1; i <= n; i++)
{
for(int j = x; j >= 0; j--)
{
if(j >= use[i]) dp[j] = max(dp[j] + lose[i], dp[j-use[i]] + win[i]); //藥劑j夠打i,可以打贏或者打輸
else dp[j] += lose[i]; //藥劑j不夠打i,只能打敗
}
}
cout << 5ll * dp[x] << endl;
return 0;
}