数据结构与算法之算法 动态规划变形 背包问题 / 最长子序列

数据结构与算法阿木 发布于 10 天前 3 次阅读


摘要:

动态规划是一种解决优化问题的强大工具,它通过将复杂问题分解为更小的子问题,并存储子问题的解以避免重复计算,从而提高算法效率。本文将围绕动态规划的两个经典变形——背包问题与最长子序列问题,进行深入解析,并通过代码实现展示其应用。

一、

背包问题与最长子序列问题是动态规划中的两个典型问题,它们在理论研究和实际应用中都有着广泛的应用。背包问题涉及如何在有限的空间内装入尽可能多的物品,而最长子序列问题则是寻找一个序列,其元素在原序列中按照一定顺序排列,且长度最长。本文将分别对这两个问题进行详细解析。

二、背包问题

背包问题可以分为两种类型:0-1背包问题和完全背包问题。

1. 0-1背包问题

0-1背包问题是指每个物品只能选择放入背包或不放入背包。其状态转移方程如下:

f[i][j] = max(f[i-1][j], f[i-1][j-w[i]] + v[i]),其中i表示物品编号,j表示剩余空间,w[i]表示物品i的重量,v[i]表示物品i的价值。

2. 完全背包问题

完全背包问题是指每个物品可以无限制地选择放入背包。其状态转移方程如下:

f[i][j] = max(f[i-1][j], f[i-1][j-w[i]] + v[i]),其中i表示物品编号,j表示剩余空间,w[i]表示物品i的重量,v[i]表示物品i的价值。

下面是0-1背包问题的Python代码实现:

python

def knapsack_01(weights, values, capacity):


n = len(weights)


dp = [[0] (capacity + 1) for _ in range(n + 1)]

for i in range(1, n + 1):


for j in range(1, capacity + 1):


if j >= weights[i - 1]:


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][capacity]

weights = [2, 3, 4, 5]


values = [3, 4, 5, 6]


capacity = 5


print(knapsack_01(weights, values, capacity))


三、最长子序列问题

最长子序列问题是指在一个序列中,找出一个子序列,其元素在原序列中按照一定顺序排列,且长度最长。其状态转移方程如下:

f[i][j] = max(f[i - 1][j], f[i - 1][j - 1] + 1),其中i表示子序列长度,j表示原序列长度。

下面是最长子序列问题的Python代码实现:

python

def longest_subsequence(nums):


n = len(nums)


dp = [[0] (n + 1) for _ in range(n + 1)]

for i in range(1, n + 1):


for j in range(1, n + 1):


if nums[i - 1] == nums[j - 1]:


dp[i][j] = dp[i - 1][j - 1] + 1


else:


dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

return dp[n][n]

nums = [1, 2, 3, 4, 5]


print(longest_subsequence(nums))


四、总结

本文对动态规划的两个经典变形——背包问题与最长子序列问题进行了详细解析,并通过代码实现展示了其应用。动态规划作为一种强大的算法工具,在解决优化问题时具有广泛的应用前景。在实际应用中,我们可以根据具体问题选择合适的动态规划方法,以提高算法效率。