返回
解决背包问题:优化思维与无效化处理
后端
2023-12-26 23:32:07
在前面的文章中,我们已经学习了什么是完全背包问题以及对应的解决方案和练习。本文将介绍一道实际问题,通过这道题来进一步强化读者对完全背包问题的一维优化思维和无效化状态的处理能力。
实际问题
有一个旅行者准备去旅行,他有 N 件物品可以选择携带,每件物品都有自己的重量和价值。旅行者的背包有 W 的重量限制,他需要选择一些物品放入背包,使得背包的总重量不超过 W,并且背包中物品的总价值最大。
分析
这是一个典型的完全背包问题。我们可以用动态规划来解决这个问题。首先,我们将物品按重量从小到大排序。然后,我们创建一个二维数组 dp,其中 dp[i][j] 表示将前 i 件物品放入一个容量为 j 的背包的最大价值。
def knapsack(items, W):
"""
Solves the complete knapsack problem.
Args:
items: A list of tuples (weight, value).
W: The maximum weight capacity of the knapsack.
Returns:
The maximum value that can be obtained by packing items into the knapsack.
"""
# Sort the items by weight.
items.sort(key=lambda item: item[0])
# Create a 2D array to store the maximum values for each item and weight capacity.
dp = [[0 for _ in range(W + 1)] for _ in range(len(items) + 1)]
# Fill in the dp array.
for i in range(1, len(items) + 1):
for j in range(1, W + 1):
if items[i - 1][0] > j:
# If the item's weight is greater than the current capacity, then we can't include it.
dp[i][j] = dp[i - 1][j]
else:
# We can either include the item or not.
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - items[i - 1][0]] + items[i - 1][1])
# Return the maximum value.
return dp[len(items)][W]
无效化状态
在某些情况下,我们可能会遇到无效化状态。例如,如果一个物品的重量为 0,那么无论背包的容量是多少,我们都不能将它放入背包中。为了处理这种无效化状态,我们可以对我们的代码进行一些修改。
def knapsack(items, W):
"""
Solves the complete knapsack problem.
Args:
items: A list of tuples (weight, value).
W: The maximum weight capacity of the knapsack.
Returns:
The maximum value that can be obtained by packing items into the knapsack.
"""
# Sort the items by weight.
items.sort(key=lambda item: item[0])
# Create a 2D array to store the maximum values for each item and weight capacity.
dp = [[0 for _ in range(W + 1)] for _ in range(len(items) + 1)]
# Fill in the dp array.
for i in range(1, len(items) + 1):
for j in range(1, W + 1):
if items[i - 1][0] > j:
# If the item's weight is greater than the current capacity, then we can't include it.
continue
else:
# We can either include the item or not.
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - items[i - 1][0]] + items[i - 1][1])
# Return the maximum value.
return dp[len(items)][W]
在这个修改后的代码中,我们在第 16 行添加了一个 continue
语句。这个语句的意思是,如果物品的重量大于背包的容量,那么我们就跳过这个物品,不考虑它。这样,我们就避免了无效化状态的发生。
练习题
-
有一个背包,重量限制为 W。有 N 件物品,每件物品的重量为 w_i,价值为 v_i。请你选择一些物品放入背包,使得背包的总重量不超过 W,并且背包中物品的总价值最大。
-
有一个仓库,里面有 N 件物品,每件物品的重量为 w_i,价值为 v_i。现在需要将这些物品装入若干个背包中,每个背包的重量限制为 W。请你将物品装入背包中,使得背包的总数量最少,并且背包中物品的总价值最大。