希赛考试网
首页 > 软考 > 软件设计师

01背包问题动态规划详解

希赛网 2024-02-20 10:50:26

01背包问题是一个经典的动态规划问题,它是一种最基本、最经典、最典型、最常用的背包问题。被称作“01背包”是因为在这个问题中,每一个物品只有选取或者不选取两个状态。本文将从多个角度分析01背包问题的动态规划解法。

入门级算法分析

首先,让我们来看一个 初步解法-暴力求解:

```python

def get_max_value(values, weights, capacity):

n = len(values)

max_value = 0

for i in range(2 ** n):

temp_value = 0

temp_weight = 0

index = i

for j in range(n):

k = index & 1

if temp_weight + weights[j] <= capacity and k == 1:

temp_value += values[j]

temp_weight += weights[j]

index >>= 1

if temp_value > max_value:

max_value = temp_value

return max_value

```

这个解法很好理解,针对这个问题中数据范围很小,物品只有两个属性,选和不选两个状态,所以一共只有 $2^n$种可能,我们枚举所有可能,找到最优解。然后针对这个算法的复杂度,我们可以发现,它需要遍历所有情况,时间复杂度为$O(2^n)$,这是非常高的复杂度。

通过暴力求解,我们很可能已经可以得到问题的解法。接下来,我们尝试用动态规划来解决这个问题。

动态规划分析

动态规划是一个分阶段求解问题的思想,可以解决多阶段决策最优化问题。比如“01背包”问题就可以采用动态规划的思想,现在我们来看一下如何用动态规划来解决这个问题。

这个问题中有两个限制条件,容量和物品个数,一个直观的想法是,我们可以把它们在两个轴上面展开,如下所示:

![image-20210912150147684](https://gitee.com/EddieWen-TB/img-repo/raw/master/img/image-20210912150147684.png)

其中,横轴表示物品个数,纵轴表示容量大小,我们可以发现,如果我们只考虑前i个物品,限制条件是j,那么最多能够承受的重量是dp[i][j],这是一个最优解。考虑第i个物品,它有选和不选两种状态:如果不选,则dp[i][j]=dp[i-1][j],它的当前最大重量只有可能等于前i-1件物品的重量;如果选,那么 dp[i][j]=dp[i-1][j-w[i]]+v[i],因为选了第i件物品后,当前的最优解就是前i-1件物品在容量为j-w[i]的条件下的最优解加上当前的价值v[i]。优化后的动态转移方程如下:

$$dp[i][j] = \max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])$$

其中,dp[i-1][j]表示不选第i个物品时的最优解,dp[i-1][j-w[i]]+v[i] 表示选择第i个物品时的最优解,取它们中的最大值就是前i个物品能够得到的最大价值。

最后,我们还需要初始化 dp 数组,即对状态数组进行设置,并将需要求的状态值赋初值,我们可以先构造一个为0的数组,然后再根据情况对数组进行设置,这个我们可以根据题目要求进行设置。

接下来,我们来看一下Python代码的实现:

```python

def knapsack(weights, values, total_weight):

n = len(weights)

dp = [[0] * (total_weight + 1) for _ in range(n)] # 初始化dp数组

# 设置dp数组初值

for weight in range(total_weight + 1):

if weights[0] > weight:

dp[0][weight] = 0

else:

dp[0][weight] = values[0]

for index in range(1, n):

for weight in range(total_weight + 1):

if weights[index] > weight:

dp[index][weight] = dp[index - 1][weight]

else:

dp[index][weight] = max(dp[index - 1][weight], dp[index - 1][weight - weights[index]] + values[index])

return dp[n - 1][total_weight]

```

微信扫一扫,领取最新备考资料


软考.png


软件设计师 资料下载
备考资料包大放送!涵盖报考指南、考情深度解析、知识点全面梳理、思维导图等,免费领取,助你备考无忧!
立即下载
软件设计师 历年真题
汇聚经典真题,展现考试脉络。精准覆盖考点,助您深入备考。细致解析,助您查漏补缺。
立即做题

软考报考咨询

微信扫一扫,定制学习计划