0-1背包详细解释加代码注释

本文详细解析了0-1背包问题的解决方法,通过动态规划算法确定在背包容量限制下,如何选择物品以使总价值最大化。文章提供了完整的算法思路及实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来源自我的博客

http://www.yingzinanfei.com/2017/03/04/0-1beibaoxiangxijieshijiadaimazhushi/

问题:

有n种物品,每种只有一个。第i种物品的体积为Vi,重量为Wi。选一些物品装到一个容量为C的背包,使得背包内物品在总体积不超过C的前提下重量尽量大。

1 <= n <= 100

1 <= Vi <= C <= 10000

1 <= Wi <= 1000000

方法:

  • 题目为求把第1,2,3,…,n个物品装到容量为C的背包中的最大重量,那么设d(i,j)表示把第i,i+1,i+2,…,n个物品装到容量为j的背包中的最大重量。答案为d(1,C)。
  • 那么在处理第i个物品时有两个选择,放入背包和不放入背包
    • 如果第i个物品不放入背包,那么d(i, j) = d(i + 1, j),表示这和把第i+1,i+2,…,n个物品装到容量为j的背包中的最大重量一样
    • 如果第i个物品放入了背包,那么要从i+1层来获得数据的话,肯定是从第i+1,i+2,…,n个物品装到容量为j-V[i]获得。因为第i个物品放入了背包,下一层时容量变小了
      • d(i+1, j-V[i])
      • 因为d(i, j)表示的含义是背包中的最大重量,因为第i个物品放入了背包,所以重量有增加,最后的表达式为d(i, j) = d(i + 1, j - V[i]) + W[i]
    • 这两种情况都有可能,那么就取最大值吧
  • d(i, j) = max{d(i + 1, j), d(i + 1, j - V[i]) + W[i]}
  • 因为第i层数据从第i+1层来,所以对i的循环要逆序,从大到小
  • 第n层的数据d(n, j)表示把第n个物品装到容量为j的背包中的最大重量,没有第n+1层了,所以直接判断此边界
    • 如果能放进且放进去的话,d(n, j) = V[n]
    • 如果不能放进或不想放进的话,d(n, j) = 0

代码

for (int j = 0; j <= C; j++){
    // 处理第n层的边界情况
    if (j >= V[n]){
        // 如果能放进去那肯定选择放进去
        d[n][j] = W[n];
    }
    else{
        // 不能放进去就为0
        d[n][j] = 0;
    }
}
for (int i = n - 1; i >= 1; i--){
    // n要逆序,从第n-1层开始
    for (int j = 0; j <= C; j++){
        // j的循环次序无所谓
        d[i][j] = d[i + 1][j];  // 先假设不放进去
        if (j >= V[i]){
            // 如果能放进去且放进去的话
            d[i][j] = max(d[i][j], d[i + 1][j - V[i]] + W[i]);
        }
    }
}

如果要合并边界和一般情况,可以加一个n + 1层,使其全部初始化为0

memset(d, 0, sizeof(d));
for (int i = n; i >= 1; i--){
    // 从第n层开始
    for (int j = 0; j <= C; j++){
        d[i][j] = d[i + 1][j];  // 先假设不放进去
        if (j >= V[i]){
            d[i][j] = max(d[i][j], d[i + 1][j - V[i]] + W[i]);
        }
    }
}
好的,以下是回溯法解决0-1背包问题的代码注释: ```python def backtrack(i, cw, items, n, w, max_w): """ 回溯算法求解0-1背包问题 :param i: 当前考虑的物品的编号 :param cw: 当前已选择的物品的重量之和 :param items: 所有物品的重量列表 :param n: 物品个数 :param w: 背包总重量 :param max_w: 当前最优解的重量之和 """ # 如果已经遍历完所有物品或者当前已选择的物品重量之和已经超过了背包总重量,则返回 if i == n or cw == w: if cw > max_w: max_w = cw return max_w # 不选当前物品 max_w = backtrack(i+1, cw, items, n, w, max_w) # 如果当前已选择的物品重量之和上当前物品的重量不超过背包总重量,则选择当前物品 if cw + items[i] <= w: # 选择当前物品,并将其重量入当前已选择的物品重量之和 max_w = backtrack(i+1, cw+items[i], items, n, w, max_w) return max_w ``` 其中,`i` 表示当前考虑的物品的编号,`cw` 表示当前已选择的物品的重量之和,`items` 是所有物品的重量列表,`n` 表示物品个数,`w` 表示背包总重量,`max_w` 是当前最优解的重量之和。 首先判断如果已经遍历完所有物品或者当前已选择的物品重量之和已经超过了背包总重量,则返回。然后,根据回溯算法的特点,我们需要分别考虑选择当前物品和不选择当前物品两种情况。如果不选择当前物品,则直接调用 `backtrack` 函数进入下一层递归。如果选择当前物品,则先判断当前已选择的物品重量之和上当前物品的重量是否超过背包总重量,如果不超过,则选择当前物品,并将其重量入当前已选择的物品重量之和,然后继续调用 `backtrack` 函数进入下一层递归。最后,将当前最优解的重量之和返回即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值