洛谷題單指南-動態規劃1-P1802 5 倍經驗日

江城伍月發表於2024-04-19

原題連結: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;
}

相關文章