01背包问题

动态规划中的核心在构建动态规划的矩阵和更新的方法。 1、矩阵行(i):表示仅考虑[0, 1, ..., i]元素。 2、矩阵列(j):表示最大容量为j。 此时dp[i][j]即表示相应的奖励,在选择i元素后,可选元素和最大容量都收缩。更新策略是外层累加i,内层增加最大容量j。可以采用滚动数组进行优化。

#include<iostream>
#include<vector>
#include<unordered_set>
using namespace std;
int main(){
    int n, m;
    cin >> n >> m;
    vector<int> nums(n, 0);
    for (int i = 0; i < n; ++i) {
        cin >> nums[i];
    }
    int k;
    cin >> k;
    vector<pair<int, int>> candy_1_2; // 表示需求的糖果数和对应牛牛的数量是1还是2
    unordered_set<int> mySet;
    for (int i = 0; i < k; ++i) {
        int connect1, connect2;
        cin >> connect1 >> connect2;  // 表示两个关联的编号
        candy_1_2.push_back({nums[connect1 - 1] + nums[connect2 - 1], 2});
        mySet.insert(connect1 - 1);
        mySet.insert(connect2 - 1);
    }
    for (int i = 0; i < n; ++i) {
        if (mySet.find(i) == mySet.end()) {
            candy_1_2.push_back({nums[i], 1});
        }
    }
    int n2 = candy_1_2.size(); // 表示可以单独选择或者不选择的项数
    vector<int> dp(m + 1, 0);
    for (int i = 0; i < n2; ++i) {  // 考虑【0, i】的闭区间内的所有元素
        vector<int> dp_before = dp;
        for (int j = 1; j <= m; ++j) {  // 此时背包的容量为j
            if (j < candy_1_2[i].first) {
                dp[j] = dp_before[j];  // 如果j较小,直接等于before
            } else {
                dp[j] = max(dp_before[j], dp_before[j - candy_1_2[i].first] + candy_1_2[i].second);
            }
        }
    }
    cout << dp[m] << endl;
    return 0;
}