586 字
3 分钟
代码随想录算法训练营第三十天 | 动态规划 Part03
🎒 0-1 背包问题
问题描述:给定物品重量和价值,背包容量为
n
,每个物品只能选一次,求在容量不超限制的前提下最大价值。
- 状态定义:
dp[i][j]
表示从前i
个物品中选择、且总重量不超过j
时的最大总价值。 - 状态转移方程:
- 不选第
i
个物品:dp[i][j] = dp[i - 1][j]
- 选第
i
个物品:dp[i][j] = dp[i - 1][j - weight[i]] + value[i]
(前提是j >= weight[i]
)
- 不选第
卡码网:46.携带研究材料
二维解法
import sysinput = sys.stdin.read
def main(): data = input().strip().split() index = 0 m = int(data[index]) # 物品数量 index += 1 n = int(data[index]) # 背包容量 index += 1
weight = [] for i in range(m): weight.append(int(data[index])) index += 1
value = [] for i in range(m): value.append(int(data[index])) index += 1
# dp[i][j] 表示前 i 个物品,容量为 j 时的最大价值 dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1): for j in range(n + 1): if j < weight[i - 1]: # 容量不足,不能选第 i 个物品 dp[i][j] = dp[i - 1][j] else: # 取选与不选两种方案的最大值 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1])
print(dp[m][n])
main()
一维解法(空间优化)
import sysinput = sys.stdin.read
def main(): data = input().strip().split() index = 0 m = int(data[index]) # 物品数量 index += 1 n = int(data[index]) # 背包容量 index += 1
weight = [] for i in range(m): weight.append(int(data[index])) index += 1
value = [] for i in range(m): value.append(int(data[index])) index += 1
# 一维数组优化:dp[j] 表示容量为 j 时的最大价值 dp = [0] * (n + 1)
for i in range(m): # 从后往前遍历,避免覆盖之前的状态 for j in range(n, weight[i] - 1, -1): dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
print(dp[n])
main()
416. 分割等和子集
LeetCode 416. Partition Equal Subset Sum
- 其实就是个 0-1 背包问题,目标和为
sum(nums) // 2
。 - 每个元素只能选择一次,问是否能正好凑出目标和。
class Solution: def canPartition(self, nums: List[int]) -> bool: total = sum(nums)
# 总和为奇数,无法平分 if total % 2 != 0: return False
target = total // 2 n = len(nums)
# dp[j] 表示容量为 j 是否可达 dp = [False] * (target + 1) dp[0] = True # 容量为 0 一定能构造
for i in range(n): # 从后往前遍历,避免覆盖状态 for j in range(target, nums[i] - 1, -1): dp[j] = dp[j] or dp[j - nums[i]]
return dp[target]
代码随想录算法训练营第三十天 | 动态规划 Part03
https://fuwari.vercel.app/posts/code_musings_day_thirty/