洛谷题单指南-动态规划1-P1802 5 倍经验日
原题链接: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;
}