162、【动态规划】AcWing ——4. 多重背包问题 I(C++/Python版本)

题目描述

在这里插入图片描述
在这里插入图片描述
原题链接:4. 多重背包问题 I

解题思路

(1)二维数组

递推公式: d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j − 0 ∗ v [ i ] ] , d p [ i − 1 ] [ j − v [ i ] ] + w [ i ] , d p [ i − 1 ] [ j − 2 ∗ v [ i ] ] + w [ i ] + . . . + d p [ i − 1 ] [ j − s [ i ] ∗ v [ i ] ] + s [ i ] ∗ w [ i ] ) dp[i][j] = max(dp[i - 1][j - 0 * v[i]], dp[i - 1][j - v[i]] + w[i], dp[i - 1][j - 2*v[i]] + w[i] + ... + dp[i - 1][j - s[i]*v[i]] + s[i]*w[i]) dp[i][j]=max(dp[i1][j0v[i]],dp[i1][jv[i]]+w[i],dp[i1][j2v[i]]+w[i]+...+dp[i1][js[i]v[i]]+s[i]w[i])

遍历时候,在最内层设置一个for循环,寻找从一个都不选到选s[i]个第i个物品时,哪种情况取得最大价值。

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

int n, m;
int dp[N][N];
int v[N], w[N], s[N];


int main() {
    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++) {
            // 一个都不选一直到选s[i]个,选择一种最大价值情况
            for(int k = 0; k <= s[i]; k++) {
            	// 注意这里的判定条件应该只为k * v[i] <= j时情况,而不能是让k * v[i] > j 时,取dp[i][j]=dp[i-1][j],因为就算k*v[i]此时大于j,但是并不能代表其他k值时也大于j导致i这个背包情况被忽略。
                if(k * v[i] <= j){
                    dp[i][j] = max(dp[i][j], dp[i - 1][j - k * v[i]] + k * w[i]);
                }
            }
        }
    }
    
    cout << dp[n][m] << endl;
    
    return 0;
    
}

Python

n, m = map(int, input().split())
v, w, s = [], [], []

for i in range(n):
    item = list(map(int, input().split()))
    v.append(item[0])
    w.append(item[1])
    s.append(item[2])

dp = [[0] * (m + 1) for _ in range(n + 1)]

for i in range(1, n + 1):
    for j in range(m + 1):
        dp[i][j] = dp[i - 1][j]
        for k in range(s[i - 1] + 1):
            if k * v[i - 1] <= j:
                dp[i][j] = max(dp[i][j], dp[i - 1][j - k * v[i - 1]] + k * w[i - 1])

print(dp[n][m])

(2)一维滚动数组

在01背包一维滚动数组的基础上,内层再多个for循环。

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

int n, m;
int dp[N];
int v[N], w[N], s[N];


int main() {
    cin >> n >> m;
    
    for(int i = 1; i <= n; i++)         cin >> v[i] >> w[i] >> s[i];
    dp[0] = 0;
    
    for(int i = 1; i <= n; i++) {
        for(int j = m; j >= 0; j--) {
            // 一个都不选一直到选s[i]个,选择一种最大价值情况
            for(int k = 0; k <= s[i] && j >= k * v[i] ; k++) {
                dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i]);
            }
        }
    }
    
    cout << dp[m] << endl;
    
    return 0;
    
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辰阳星宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值