ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-09-10 13:02:55  阅读:129  来源: 互联网

标签:int 大红大紫 08 ZJSU cin -- mathcal void dp


动态规划

\(\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]);
}

多重背包

每种物品数量给定。

  • 未优化版,\(\mathcal{O}(N*M*S)\) ,其中 \(S\) 为数量。
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]);
}
  • 使用二进制优化,\(\mathcal{O}(N*M*logS)\) ,其中 \(S\) 为数量。
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]);
}
  • 使用单调队列优化, \(\mathcal{O}(N*M)\) 。
 //使用单调队列优化
#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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有