其他分享
首页 > 其他分享> > 【ZJSU - 大红大紫:ACM - Template】比赛用模板08(W):动态规划

【ZJSU - 大红大紫:ACM - Template】比赛用模板08(W):动态规划

作者:互联网

动态规划

\(\tt{}0/1\) 背包

\(N\) 件物品中选取,使得选取物品总体积不超过 \(M\) 的前提下,使得物品的价值总和最大。每种物品一件, \(\mathcal{O}(N*M)\) 。

int n, m, dp[N]; int v[N], w[N];
void Zero_bag() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i) cin >> v[i] >> w[i];
    for (int i = 1; i <= n; ++ i)
        for(j = m; j >= v[i]; -- j)
            dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}

完全背包

每种物品无限, \(\mathcal{O}(N*M)\) 。

int n, m, dp[N]; int v[N], w[N];
void Cp_bag() {
    cin >> n >> m;
    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 <= m; ++ j)
            dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}

多重背包

每种物品数量给定。

int n, m, dp[N][N]; int v[N], w[N], s[N];
void Multi_bag() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i) cin >> v[i] >> w[i] >> s[i];
    for (int i = 1; i <= n; ++ i)
        for (int j = 0; j <= m; ++ j)
            for (int k = 0; k <= s[i] && k * v[i] <= j; ++ k)
                dp[i][j] = max(dp[i][j], dp[i - 1][j - k * v[i]] + k * w[i]);
}
int n, m, dp[N]; int cnt, v[N], w[N];
void Multi_bag() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i) {
        int vv, ww, ss; cin >> vv >> ww >> ss; // vv体积,ww价值,ss为数量,均临时储存
        for (int k = 1; k <= ss; ss -= k, k *= 2) {
            v[++ cnt] = vv * k;
            w[cnt] = ww * k;
        }
        v[++ cnt] = vv * ss;
        w[cnt] = ww * ss;
    }
    n = cnt;
    for (int i = 1; i <= n; ++ i)
        for (int j = m; j >= v[i]; -- j)
            dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
 //使用单调队列优化
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
int n, m, dp[N], V[N], W[N], C[N], q[N];

int clac (int i, int u, int k) { return dp[u + k * V[i]] - k * W[i]; }
int main() {
    ios_base::sync_with_stdio(0); cin.tie(0);
    cin >> n >> m;
    memset(dp, 0xcf, sizeof dp);
    dp[0] = 0;
    
    for (int i = 1; i <= n; ++ i) {
        cin >> V[i] >> W[i] >> C[i];
        for (int u = 0; u < V[i]; ++ u) {
            int l = 1, r = 0;
            int maxp = (m - u) / V[i];
            for (int k = maxp - 1; k >= max(maxp - C[i], 0); -- k) {
                while (l <= r && clac(i, u, q[r]) <= clac(i, u, k)) -- r;
                q[++ r] = k;
            }
            for (int p = maxp; p >= 0; -- p) {
                while (l <= r && q[l] > p - 1) ++ l;
                if (l <= r)
                    dp[u + p * V[i]] = max(dp[u + p * V[i]], clac(i, u, q[l]) + p * W[i]);
                if (p - C[i] - 1 >= 0) {
                    while (l <= r && clac(i, u, q[r]) <= clac(i, u, p - C[i] - 1)) -- r;
                    q[++ r] = p - C[i] - 1;
                }
            }
        }
    }
    int ans = 0;
    for (int i = 1; i <= m; ++ i) ans = max(ans, dp[i]);
    cout << ans << endl;
    return 0;
}

分组背包:

给出分组情况,每组至多取一件物品。\(\mathcal{O}(N*M*S)\) 。

int n, m, dp[N]; int v[N][N], w[N][N], s[N];
void Group_bag() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i) {
        cin >> s[i];
        for (int j = 1; j <= s[i]; ++ j) cin >> v[i][j] >> w[i][j];
    }
    for (int i = 1; i <= n; ++ i)
        for (int j = m; j >= 0; -- j)
            for (int k = 1; k <= s[i]; ++ k)
                if (v[i][k] <= j) dp[j] = max(dp[j], dp[j - v[i][k]] + w[i][k]);
}

标签:int,大红大紫,08,ZJSU,cin,--,mathcal,void,dp
来源: https://www.cnblogs.com/WIDA/p/16676292.html