背包问题递归、备忘录、动态规划Python实现
时间: 2023-09-07 13:04:47 浏览: 214
### 回答1:
背包问题是经典的动态规划问题,可以用递归、备忘录和动态规划三种方式来解决。下面是Python实现:
递归:
```python
def knapsack(w, v, i, j):
if i == 0 or j == 0:
return 0
if w[i-1] > j:
return knapsack(w, v, i-1, j)
else:
return max(knapsack(w, v, i-1, j), v[i-1] + knapsack(w, v, i-1, j-w[i-1]))
```
备忘录:
```python
def knapsack(w, v, i, j, memo):
if i == 0 or j == 0:
return 0
if memo[i][j] != -1:
return memo[i][j]
if w[i-1] > j:
memo[i][j] = knapsack(w, v, i-1, j, memo)
else:
memo[i][j] = max(knapsack(w, v, i-1, j, memo), v[i-1] + knapsack(w, v, i-1, j-w[i-1], memo))
return memo[i][j]
n = 4
w = [2, 1, 3, 2]
v = [12, 10, 20, 15]
W = 5
memo = [[-1 for j in range(W+1)] for i in range(n+1)]
print(knapsack(w, v, n, W, memo))
```
动态规划:
```python
def knapsack(w, v, W):
n = len(w)
dp = [[0 for j in range(W+1)] for i in range(n+1)]
for i in range(1, n+1):
for j in range(1, W+1):
if w[i-1] > j:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(dp[i-1][j], v[i-1] + dp[i-1][j-w[i-1]])
return dp[n][W]
n = 4
w = [2, 1, 3, 2]
v = [12, 10, 20, 15]
W = 5
print(knapsack(w, v, W))
```
### 回答2:
背包问题是一个经典的组合优化问题,即在有限的资源约束下,如何选择一组物品放入背包中,使得价值最大化。
对于背包问题的解法,可以使用递归、备忘录和动态规划三种方法来实现。
1. 递归方法:
最简单的方法是使用递归来解决背包问题。该方法会尝试将每个物品放入背包,并计算放入和不放入每个物品的结果,然后选择价值最大的方案。递归方法的缺点是重复计算,速度较慢。
2. 备忘录方法:
为了避免递归方法中的重复计算,可以使用备忘录方法。该方法在计算过程中,将每个子问题的结果保存在一个HashMap中,下次遇到相同的问题时可以直接使用保存的结果。备忘录方法可以有效减少重复计算,提高计算效率。
3. 动态规划方法:
动态规划是解决背包问题最常用的方法,也是最高效的方法。该方法使用一个二维数组来保存每个子问题的结果。通过迭代计算每个子问题的最优解,最终得到整个问题的最优解。动态规划方法的优点是计算效率高,可以处理更大规模的问题。
下面是使用Python实现背包问题的递归、备忘录和动态规划方法的示例代码:
1. 递归方法示例代码如下:
```python
def knapsack_recursion(weight, value, capacity, n):
if n == 0 or capacity == 0:
return 0
if weight[n-1] > capacity:
return knapsack_recursion(weight, value, capacity, n-1)
else:
return max(value[n-1] + knapsack_recursion(weight, value, capacity - weight[n-1], n-1),
knapsack_recursion(weight, value, capacity, n-1))
```
2. 备忘录方法示例代码如下:
```python
def knapsack_memoization(weight, value, capacity, n, memo):
if n == 0 or capacity == 0:
return 0
if memo[n][capacity] != -1:
return memo[n][capacity]
if weight[n-1] > capacity:
memo[n][capacity] = knapsack_memoization(weight, value, capacity, n-1, memo)
else:
memo[n][capacity] = max(value[n-1] + knapsack_memoization(weight, value, capacity - weight[n-1], n-1, memo),
knapsack_memoization(weight, value, capacity, n-1, memo))
return memo[n][capacity]
```
3. 动态规划方法示例代码如下:
```python
def knapsack_dynamic_programming(weight, value, capacity, n):
dp = [[0] * (capacity + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
for j in range(1, capacity + 1):
if weight[i-1] > j:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(value[i-1] + dp[i-1][j - weight[i-1]], dp[i-1][j])
return dp[n][capacity]
```
以上是背包问题递归、备忘录和动态规划三种方法的Python实现示例,它们分别采用不同的计算策略来求解背包问题,并具有不同的计算效率和复杂度。
### 回答3:
背包问题是一个经典的组合优化问题,在给定一组物品和一个固定容量的背包的情况下,要求在限制总体积不能超过背包容量的前提下,使得背包所放物品的总价值最高。
下面我将分别介绍背包问题的递归、备忘录和动态规划的Python实现。
1. 递归实现:
递归实现背包问题的思路是将问题分解为若干子问题,并通过递归求解子问题再合并得到最终解。
```python
def knapsack_recursion(weights, values, capacity, n):
# 如果没有物品或者背包容量为0,则返回0
if n == 0 or capacity == 0:
return 0
# 如果当前物品的重量大于背包容量,则该物品不能放入背包中
if weights[n-1] > capacity:
return knapsack_recursion(weights, values, capacity, n-1)
# 否则,比较放入当前物品和不放入当前物品的情况,选择价值最大的方案
else:
return max(values[n-1] + knapsack_recursion(weights, values, capacity-weights[n-1], n-1),
knapsack_recursion(weights, values, capacity, n-1))
```
2. 备忘录实现:
备忘录实现背包问题的思路是在递归的过程中,用一个字典(称为备忘录)来记录已经计算过的子问题的结果,避免重复计算。
```python
def knapsack_memoization(weights, values, capacity, n, memo):
# 如果已经计算过该子问题的结果,则直接返回
if (n, capacity) in memo:
return memo[(n, capacity)]
if n == 0 or capacity == 0:
result = 0
elif weights[n-1] > capacity:
result = knapsack_memoization(weights, values, capacity, n-1, memo)
else:
result = max(values[n-1] + knapsack_memoization(weights, values, capacity-weights[n-1], n-1, memo),
knapsack_memoization(weights, values, capacity, n-1, memo))
# 将计算结果保存到备忘录中
memo[(n, capacity)] = result
return result
# 调用方式
memo = {}
knapsack_memoization(weights, values, capacity, n, memo)
```
3. 动态规划实现:
动态规划实现背包问题的思路是用一个二维数组来保存子问题的结果,根据子问题的结果递推出更复杂的问题的解,直到得到最优解。
```python
def knapsack_dynamic(weights, values, capacity):
n = len(weights)
# 创建一个二维数组来保存子问题的结果
dp = [[0 for _ in range(capacity+1)] for _ in range(n+1)]
for i in range(1, n+1):
for j in range(1, capacity+1):
if weights[i-1] > j:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(values[i-1] + dp[i-1][j-weights[i-1]], dp[i-1][j])
return dp[n][capacity]
# 调用方式
knapsack_dynamic(weights, values, capacity)
```
以上就是背包问题递归、备忘录和动态规划的Python实现。这些方法都可以有效地解决背包问题,但其时间和空间复杂度不同。递归方法的时间复杂度为O(2^n),备忘录和动态规划方法的时间复杂度为O(n*capacity),备忘录方法使用了额外的空间来存储备忘录,空间复杂度为O(n*capacity)。动态规划方法的空间复杂度也是O(n*capacity),但相较于备忘录方法,动态规划方法更加高效。
阅读全文