蓝桥303求解01背包问题

题目描述

求解 01 背包问题

题目描述
实现一个算法求解 01 背包问题。背包问题的介绍如下:
已知一个容量为 totalweight的背包,有不同重量不同价值的物品,问怎样在背包容量限制下达到利益最大化。
01 背包问题要求每个物品只有一个,可以选择放入或者不放入背包。

输入描述
第一行为两个数字 totalweight、N,均不超过 1000。
totalweight 含义见题干,N 为物品数量。

接下来 N 行,每行两个数字 Wi 、Vi,均不超过 1000。含义见题干。

输出描述
输出一行,为在背包容量限制下的最大化利益。

输入输出样例
示例
输入
8 5
3 4
5 5
1 2
2 1
2 3

输出
10

运行限制
最大运行时间:1s
最大运行内存: 256M

本题目代码

#include <iostream>  
#include <vector>  
#include <algorithm>  
  
using namespace std;  
  
int main() {  
    int totalweight, N;  
    cin >> totalweight >> N;  
  
    vector<int> weights(N), values(N);  
    for (int i = 0; i < N; ++i) {  
        cin >> weights[i] >> values[i];  
    }  
  
    // 创建一个二维DP表,dp[i][j]表示从前i个物品中选择,在容量为j的背包中能达到的最大价值  
    vector<vector<int>> dp(N + 1, vector<int>(totalweight + 1, 0));  
  
    // 填充DP表  
    for (int i = 1; i <= N; ++i) {  
        for (int j = 1; j <= totalweight; ++j) {  
            if (weights[i - 1] <= j) {  
                // 如果当前物品可以放入背包,则比较放入和不放入两种情况下的最大价值  
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]);  
            } else {  
                // 如果当前物品太重,不能放入背包,则继承前一个物品的结果  
                dp[i][j] = dp[i - 1][j];  
            }  
        }  
    }  
  
    // 输出最大价值,即dp[N][totalweight]  
    cout << dp[N][totalweight] << endl;  
  
    return 0;  
}

本题目代码解释

这个程序首先读取背包的总容量 totalweight 和物品的数量 N,然后读取每个物品的重量 Wi 和价值 Vi。接下来,它使用一个二维动态规划表 dp 来存储子问题的解,其中 dp[i][j] 表示从前 i 个物品中选择,在容量为 j 的背包中能达到的最大价值。

通过两层循环,程序填充了 dp 表。外层循环遍历每个物品,内层循环遍历所有可能的背包容量。对于每个物品和每个容量,程序检查是否可以将该物品放入背包中(即检查 weights[i - 1] <= j),如果可以,则比较放入和不放入该物品时的最大价值,并更新 dp[i][j]。如果物品太重无法放入背包,则继承前一个物品的结果。

最后,程序输出 dp[N][totalweight],即在所有物品和背包容量限制下的最大化利益。

考研中的01背包问题

给定:

一个背包,其最大承重为 c。
一组物品,每个物品 i 有其重量 w[i] 和价值 v[i]。
每个物品只能选择装入或不装入背包。
目标:
在不超过背包最大承重 W 的前提下,选择装入背包的物品,使得背包中物品的总价值最大。

DP递推公式

m[i][j]表示的是在考虑前i个物品时,背包容量为j的情况下能达到的最大价值。

m[i][j]=0                                                                 i=0&j=0

m[i][j]=m[i-1][j]                                                       w[i]>j

m[i][j]=max(m[i−1][j],m[i−1][j−w[i−1]]+v[i−1])         w[i]<=j

这里,m[i-1][j]表示不选择第i个物品时,背包容量为j的最大价值;m[i-1][j-w[i-1]] + v[i-1]表示选择第i个物品时,背包容量为j的最大价值(这里假设第i个物品可以被放入背包,即j-w[i-1]非负)。我们通过比较这两种情况来决定是否选择第i个物品。

01背包代码

const int maxSize = 100;

int pack(int n, int c, int v[], int w[], int m[][maxSize]) {
    for (int i = 1; i <= n; i++)
        m[i][0] = 0;

    for (int i = 0; i <= c; i++)
        m[0][i] = 0;

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= c; j++) {
            if (w[i - 1] > j)
                m[i][j] = m[i - 1][j];
            else
                m[i][j] = std::max(m[i - 1][j], m[i - 1][j - w[i - 1]] + v[i - 1]);
        }

    return 0;
}



void traceBack(int n, int c, int w[], int m[][maxSize], int x[]) {
    for (int i = n; i >= 1; --i)
        if (m[i][c] == m[i - 1][c])
            x[i] = 0;
        else {
            x[i] = 1;
            c -= w[i];
        }
}

01背包DP表格

假设我们有4个物品,背包容量为5,物品的重量和价值分别如下:

  • 物品1: 重量1,价值2
  • 物品2: 重量2,价值3
  • 物品3: 重量3,价值4
  • 物品4: 重量4,价值5
012345
0000000
1022222(选择物品1或不选)
2023355(选择物品2或之前的选择)
3023457(选择物品3或之前的选择) 
4023459(选择物品4或之前的选择)

表格的每一行代表考虑了某个数量的物品时的状态,每一列代表背包的不同容量。m[i][j]的值表示在考虑前i个物品且背包容量为j时能达到的最大价值。

  • 第一行(i=0)和第一列(j=0)都初始化为0,因为没有任何物品或背包容量为0时,价值自然是0。
  • 对于每一行(除了第一行),我们从左到右填充值。如果当前物品的重量大于背包的当前容量(w[i-1] > j),则不选择该物品,价值与前一行相同(m[i][j] = m[i-1][j])。
  • 否则,我们比较两种情况:不选择当前物品(m[i-1][j])和选择当前物品(m[i-1][j-w[i-1]] + v[i-1]),并选择其中的较大值。

在上面的表格中,你可以看到:

  • 在考虑物品1时,只有当背包容量至少为1时,我们才能选择物品1(价值为2)。
  • 在考虑物品2时,如果背包容量至少为2,我们可以选择物品2(价值为3),或者如果背包容量不足以容纳物品2但足以容纳物品1,则选择物品1。
  • 类似地,对于物品3和物品4,我们根据背包的当前容量和物品的重量/价值来决定是否选择它们。

最终,m[4][5]的值(即表格的右下角)给出了在背包容量为5时,选择所有物品(或其中的某些物品)能得到的最大价值,这里是9。

  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值