动态规划之01背包问题及其优化(python实现)

动态规划之01背包问题及其优化(python实现)

**背包问题(**Knapsack problem)是一种组合优化的NP完全问题。
问题描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。

解决思路:动态规划,对每一件物品遍历背包容量,当背包可容纳值大于等于当前物品,与之前已放进去的物品所得价值进行对比,考虑是否需要置换。

递归定义如下:
这里写图片描述

python实现算法如下:

def bag(n, c, w, v):
    """
    测试数据:
    n = 6  物品的数量,
    c = 10 书包能承受的重量,
    w = [2, 2, 3, 1, 5, 2] 每个物品的重量,
    v = [2, 3, 1, 5, 4, 3] 每个物品的价值
    """
    # 置零,表示初始状态
    value = [[0 for j in range(c + 1)] for i in range(n + 1)]
    for i in range(1, n + 1):
        for j in range(1, c + 1):
            value[i][j] = value[i - 1][j]
            # 背包总容量够放当前物体,遍历前一个状态考虑是否置换
            if j >= w[i - 1] and value[i][j] < value[i - 1][j - w[i - 1]] + v[i - 1]:
                value[i][j] = value[i - 1][j - w[i - 1]] + v[i - 1]
    for x in value:
        print(x)
    return value

输入测试数据结果如下:最大价值为15
这里写图片描述

接下来,输出背包里所放的物品,只需从尾遍历物品,当value大于上一行同样位置的value时,表示放进该物品

代码如下:

def show(n, c, w, value):
    print('最大价值为:', value[n][c])
    x = [False for i in range(n)]
    j = c
    for i in range(n, 0, -1):
        if value[i][j] > value[i - 1][j]:
            x[i - 1] = True
            j -= w[i - 1]
    print('背包中所装物品为:')
    for i in range(n):
        if x[i]:
            print('第', i+1, '个,', end='')

输出结果:
这里写图片描述

以上时间复杂度为O(cn),已经不能再优化了。但空间复杂度O(cn)可以优化为O(c)。
思路:尾部迭代,每个状态表示上一次的最佳结果。
实现代码如下;

def bag1(n, c, w, v):
    values = [0 for i in range(c+1)]
    for i in range(1, n + 1):
        for j in range(c, 0, -1):
            # 背包总容量够放当前物体,遍历前一个状态考虑是否置换,这里的value[j]即为上一次最佳结果
            if j >= w[i-1]:
                values[j] = max(values[j-w[i-1]]+v[i-1], values[j])
    return values

完整代码:

#coding:utf-8

def bag(n, c, w, v):
    """
    测试数据:
    n = 6  物品的数量,
    c = 10 书包能承受的重量,
    w = [2, 2, 3, 1, 5, 2] 每个物品的重量,
    v = [2, 3, 1, 5, 4, 3] 每个物品的价值
    """
    # 置零,表示初始状态
    value = [[0 for j in range(c + 1)] for i in range(n + 1)]
    for i in range(1, n + 1):
        for j in range(1, c + 1):
            value[i][j] = value[i - 1][j]
            # 背包总容量够放当前物体,遍历前一个状态考虑是否置换
            if j >= w[i - 1] and value[i][j] < value[i - 1][j - w[i - 1]] + v[i - 1]:
                value[i][j] = value[i - 1][j - w[i - 1]] + v[i - 1]
    for x in value:
        print(x)
    return value

def show(n, c, w, value):
    print('最大价值为:', value[n][c])
    x = [False for i in range(n)]
    j = c
    for i in range(n, 0, -1):
        if value[i][j] > value[i - 1][j]:
            x[i - 1] = True
            j -= w[i - 1]
    print('背包中所装物品为:')
    for i in range(n):
        if x[i]:
            print('第', i+1, '个,', end='')

def bag1(n, c, w, v):
    values = [0 for i in range(c+1)]
    for i in range(1, n + 1):
        for j in range(c, 0, -1):
            # 背包总容量够放当前物体,遍历前一个状态考虑是否置换
            if j >= w[i-1]:
                values[j] = max(values[j-w[i-1]]+v[i-1], values[j])
    return values


if __name__ == '__main__':
    n = 6
    c = 10
    w = [2, 2, 3, 1, 5, 2]
    v = [2, 3, 1, 5, 4, 3]
    value = bag(n, c, w, v)
    # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    # [0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2]
    # [0, 0, 3, 3, 5, 5, 5, 5, 5, 5, 5]
    # [0, 0, 3, 3, 5, 5, 5, 6, 6, 6, 6]
    # [0, 5, 5, 8, 8, 10, 10, 10, 11, 11, 11]
    # [0, 5, 5, 8, 8, 10, 10, 10, 12, 12, 14]
    # [0, 5, 5, 8, 8, 11, 11, 13, 13, 13, 15]
    show(n, c, w, value)
    # 最大价值为: 15
    # 背包中所装物品为:
    # 第 2 个,第 4 个,第 5 个,第 6 个,
    print('\n空间复杂度优化为N(c)结果:', bag1(n, c, w, v))
    #空间复杂度优化为N(c)结果: [0, 5, 5, 8, 8, 11, 11, 13, 13, 13, 15]

如有错误,欢迎指正和交流~

### 回答1: 下面是Python实现01背包问题: ```python def knapsack(wt, val, W, n): # 创建 dp 数组 dp = [[0 for x in range(W + 1)] for y in range(n + 1)] # 填充 dp 数组 for i in range(n + 1): for j in range(W + 1): if i == 0 or j == 0: dp[i][j] = 0 elif wt[i - 1] <= j: dp[i][j] = max(val[i - 1] + dp[i - 1][j - wt[i - 1]], dp[i - 1][j]) else: dp[i][j] = dp[i - 1][j] # 返回最大价值 return dp[n][W] ``` 其中,`wt`是物品重量的列表,`val`是物品价值的列表,`W`是背包容量,`n`是物品数量。函数返回最大价值。 ### 回答2: 01背包问题是一个经典的动态规划问题,常被用于解决背包问题。解决该问题的方法有很多,其中一种常见的方法是使用Python语言进行编程。 在解决01背包问题时,需要定义一个二维数组dp来保存每个状态的最优值。其中dp[i][j]表示在前i个物品中,总重量不超过j的情况下,能够获得的最大价值。初始时,将dp数组所有元素初始化为0。 然后,需要使用一个循环来遍历每个物品,并更新dp数组。对于每个物品,可以选择将其放入背包中,也可以选择不放入背包中。如果选择放入背包中,对应的状态转移方程为:dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]),其中w[i]表示第i个物品的重量,v[i]表示第i个物品的价值。如果选择不放入背包中,对应的状态转移方程为:dp[i][j] = dp[i-1][j]。 最后,通过遍历完所有物品后,dp[n][m]即表示在前n个物品中,总重量不超过m的情况下,能够获得的最大价值。代码如下所示: ```python def knapSack(W, wt, val, n): dp = [[0 for j in range(W + 1)] for i in range(n + 1)] for i in range(1, n + 1): for w in range(1, W + 1): if wt[i - 1] <= w: dp[i][w] = max(val[i - 1] + dp[i - 1][w - wt[i - 1]], dp[i - 1][w]) else: dp[i][w] = dp[i - 1][w] return dp[n][W] ``` 以上就是使用Python解决01背包问题的一个简单示例。通过动态规划的思想,可以高效地求解背包问题,得到最优解。 ### 回答3: 01背包问题是一个经典的动态规划问题,常用于解决资源分配的优化问题。假设我们有一个背包,可以装载一定重量的物品,现在有N个物品,每个物品的重量分别是w1,w2,...,wn,价值分别是v1,v2,...,vn。我们需要选择一些物品放入背包中,使得物品总重量不超过背包的容量,同时价值最大化。 为了解决01背包问题,可以使用二维数组dp[i][j]表示前i个物品放入容量为j的背包中所能得到的最大价值。其中i表示物品的编号,j表示背包的容量。那么dp[i][j]的递推关系如下: 1. 当i=0或j=0时,dp[i][j] = 0。表示没有物品可选择或者背包容量为0时,最大价值为0。 2. 当wi > j时,dp[i][j] = dp[i-1][j]。如果当前物品的重量大于背包容量,那么无法选择放入该物品,最大价值与前i-1个物品一样。 3. 当wi <= j时,dp[i][j] = max(dp[i-1][j], dp[i-1][j-wi]+vi)。如果当前物品的重量小于等于背包容量,我们可以选择放入该物品或者不放入该物品。选择放入该物品时,最大价值为前i-1个物品放入容量为j-wi的背包中的最大价值加上当前物品的价值;选择不放入该物品时,最大价值与前i-1个物品一样。 最终结果为dp[N][V],其中N表示物品的个数,V表示背包的最大容量。可以使用循环遍历的方式计算dp[i][j],从而得到问题的最优解。 使用Python实现01背包问题的代码如下: ```python def knapsack(N, V, w, v): dp = [[0] * (V + 1) for _ in range(N + 1)] for i in range(1, N + 1): for j in range(1, V + 1): if w[i - 1] > j: dp[i][j] = dp[i - 1][j] else: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i - 1]] + v[i - 1]) return dp[N][V] N = 4 # 物品的个数 V = 5 # 背包的容量 w = [2, 1, 3, 2] # 每个物品的重量 v = [3, 2, 4, 2] # 每个物品的价值 max_value = knapsack(N, V, w, v) print("背包能够装载的最大价值为:", max_value) ``` 以上代码实现了基于动态规划01背包问题的解法,并输出了背包能够装载的最大价值。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值