算法价值5-背包问题

0/1背包问题是一个经典的组合优化问题,它可以描述为在给定一组物品和一个背包容量的情况下,选择哪些物品放入背包,以使得放入的物品总价值最大,且总重量不超过背包容量。

具体来说,问题可以描述如下:

  • 给定n个物品,每个物品有一个重量(weight)和一个价值(value)。
  • 给定一个背包容量(capacity)。
  • 每个物品只能选择放入或不放入背包,不能切割。
  • 目标是找到一种放置方式,使得放入背包的物品总价值最大,且总重量不超过背包容量。

数学表示为:

\text{maximize} \sum_{i=1}^{n} v_i x_i

\text{subject to} \sum_{i=1}^{n} w_i x_i \leq W

x_i \in \{0, 1\}

其中:

  • v_i 表示物品i的价值;
  • w_i 表示物品i的重量;
  • W 表示背包的容量;
  • x_i 表示物品i是否放入背包,取值为0或1。

0/1背包问题属于NP完全问题,其解决方案涉及到动态规划等算法。动态规划方法通常使用一个二维数组来记录在每个阶段(每个物品的考虑阶段)的最优解,通过填表的方式逐步求解问题。这种方法的时间复杂度为O(nW),其中n是物品数量,W是背包容量。

虽然0/1背包问题在最优子结构和重叠子问题方面具有动态规划问题的特点,但由于其状态空间较大,对于大规模问题,可能需要使用其他优化方法或近似算法。

参考题

Description 

已知n个物体{1,2,3....n}与一个背包。物体i的重量为Wi > 0,价值为Pi > 0 (i=1,2,...n),背包容量为M > 0。

求在不超过背包容量的情况下,使得装进去的物体的价值最高。

Input 

第一行为一个正整数N,表示有几组测试数据。 每组测试数据的第一行为两个整数n和M,0<n<=20, 0<M<100000. 再下去的n行每行有两个整数Wi和Pi, 0<Wi,Pi<10000. 

Output 

对于每组测试数据,输出一行,只含一个整数,表示装进去物体的价值最高值。 

Sample Input 

1
5 10
2 6
2 3
6 5
5 4
4 6

Sample Output 

15 

代码:

def knapsack(n, M, weights, values):
    dp = [[0] * (M + 1) for _ in range(n + 1)]

    for i in range(1, n + 1):
        for j in range(1, M + 1):
            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]

    return dp[n][M]

# 示例输入数据写死在程序里
test_cases = 1
data = [
    (5, 10, [(2, 6), (2, 3), (6, 5), (5, 4), (4, 6)])
]

for i in range(test_cases):
    n, M, items = data[i]
    weights, values = zip(*items)
    result = knapsack(n, M, weights, values)
    print(result)

结果:

15

关键解释:

在动态规划的解法中,dp[i][j] 表示在考虑前 i 个物品,且当前背包总容量为 j 的情况下,可以获得的最大价值。这里的 j 表示的是当前背包的总容量,而不是剩余容量。在考虑每个物品时,j 表示的是当前背包的总容量。

对于这个问题,我们是自底向上地填充一个二维数组 dp,其中 dp[i][j] 表示在考虑前 i 个物品,且当前背包总容量为 j 的情况下,可以获得的最大价值。在这个过程中,j 是逐渐变大的,表示我们逐步考虑越来越大的背包容量。

对于递推关系:

  • 如果 weights[i - 1] <= j,表示当前物品 i 的重量不超过当前背包容量 j,那么我们可以选择装入物品 i 或不装入物品 i,取两者中价值的更大者

    1. dp[i - 1][j] 表示不装入物品 i,直接继承前 i-1 个物品时背包容量为 j 时的最大价值。

    2. dp[i - 1][j - weights[i - 1]] + values[i - 1] 表示装入物品 i,当前总价值增加 values[i - 1],也就是说找得到一个大于等于0的数 j - weights[i - 1],因此dp[i - 1][j - weights[i - 1]]的值也是存在的。
  • 如果 weights[i - 1] > j,表示当前物品 i 的重量超过了当前背包容量 j,那么我们不能装入物品 i,只能继承前 i-1 个物品时背包容量为 j 时的最大价值。

结论:

在整个过程中,我们填充了一个二维数组,最终 dp[n][M] 就是在考虑n个物品,且背包容量为 M 时的最大价值

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

dracularking

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

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

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

打赏作者

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

抵扣说明:

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

余额充值