动态规划-背包DP

背包DP是线性DP中一种特殊的DP。

01背包

最基础的背包,有 \(n\) 件物品,背包容量为 \(V\),每件物品只有一件。可以使用空间优化,一般是原地滚动,此时注意容量需要从后往前更新,否则会一个状态更新多次。时间复杂度为 \(O(nV)\)

核心代码

void solve() {
    int n, V;
    cin >> n >> V;
    for (int i = 1; i <= n; i++) {
        cin >> v[i] >> w[i];
    }
    for (int i = 1; i <= n; i++) {
        for (int j = V; j >= v[i]; j--) {            // 注意倒序更新
            dp[j] = max(dp[j], dp[j - v[i]] + w[i]); // 体积均为j,取价值最大的
        }
    }
    cout << dp[V] << "\n";
}

例题
装箱问题
01背包问题
开心的金明
采药

完全背包

\(n\) 件物品,背包容量为 \(V\),每件物品有无穷件。可以使用空间优化,一般是原地滚动,与01背包恰好相反,此时容量从前往后更新即可。复杂度为 \(O(nV)\)

核心代码

void solve() {
    int n, V;
    cin >> n >> V;
    for (int i = 1; i <= n; i++) {
        cin >> v[i] >> w[i];
    }
    for (int i = 1; i <= n; i++) {
        for (int j = v[i]; j <= V; j++) {
            dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
        }
    }
    cout << dp[V] << "\n";
}

例题
完全背包问题

分组背包

\(n\) 组物品,背包容量为 \(V\),每组物品只能选一个。需要注意循环顺序,先对容量循环,再对每一组中的物品循环,因为每组中的物品相当于一组的一个状态,这些状态之间是互斥的。时间复杂度为 O(\(\sum n \times V\))。

核心代码

void solve() {
    int N, V, S;
    cin >> N >> V;
    vector<int> v[N + 1], w[N + 1], dp(V + 1);
    for (int i = 1; i <= N; i++) {
        cin >> S;
        v[i].resize(S);
        w[i].resize(S);
        for (int j = 0; j < S; j++) {
            cin >> v[i][j] >> w[i][j];
        }
    }

    for (int i = 1; i <= N; i++) {
        for (int j = V; j >= 0; j--) {
            for (int k = 0; k < v[i].size(); k++) {
                if (j >= v[i][k]) {
                    dp[j] = max(dp[j], dp[j - v[i][k]] + w[i][k]);
                }
            }
        }
    }

    cout << dp[V] << "\n";
}

例题
分组背包问题
小红升装备
小红组比赛

多重背包

\(n\) 组物品,背包容量为 \(V\),每组物品有有限个,其重量和价值相同。循环顺序为先对每一组中的物品循环,再对容量循环,若将多重背包中每组物品单独拿出来,可以看作01背包,而将物品进行组合可看作分组背包。时间复杂度为 O(\(\sum n \times V\))。可对每组中物品的组合进行优化,降低时间复杂度。

核心代码

void solve() {
    int N, V;
    cin >> N >> V;
    vector<int> v(N + 1), w(N + 1), s(N + 1), dp(V + 1);
    for (int i = 1; i <= N; i++) {
        cin >> v[i] >> w[i] >> s[i];
    }

    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= s[i]; j++) {
            for (int k = V; k >= v[i]; k--) {
                dp[k] = max(dp[k], dp[k - v[i]] + w[i]);
            }
        }
    }
    cout << dp[V] << "\n";
}

例题:
多重背包问题 I

posted @ 2024-08-01 18:58  catting123  阅读(108)  评论(0)    收藏  举报