二維費用揹包問題

弱弱的Ray發表於2024-07-30

寵物小精靈之收服

題解:設狀態 \(dp[i][j][k]\) 表示從前 \(i\) 個物品中選擇,物品的費用 \(1\)\(j\),費用 \(2\)\(k\) 的最大選擇數量。

則狀態轉移方程為:

\[dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - v_1[i]][k - v_2[i]] + 1) \]

跟普通01揹包一樣,第一維可以直接最佳化掉。
第一問的答案顯然為 \(dp[n][m - 1]\) (注意本題中體力不能為0),第二問的答案列舉滿足 \(dp[n][i] = dp[n][m - 1]\) 的最大的 \(m - i\) 即為答案。

AC程式碼:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 1010;
int dp[N][N];
int v[N], w[N];

void solve() {
    int n, m, k;
    cin >> n >> m >> k;
    for (int i = 1; i <= k; i ++) {
        cin >> v[i] >> w[i];
    }
    
    for (int i = 1; i <= k; i ++) {
        for (int j = n; j >= v[i]; j --) {
            for (int t = m - 1; t >= w[i]; t --) {
                dp[j][t] = max(dp[j][t], dp[j - v[i]][t - w[i]] + 1);
            }
        }
    }
    
    int res = 1e9;
    for (int i = 0; i < m; i ++) {
        if(dp[n][i] == dp[n][m - 1]) {
            res = min(res, i);
            break;
        }
    }
    
    cout << dp[n][m - 1] << " " << m - res << endl;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    solve();
}

相關文章