(一) 动态规划——背包专题
导语:动态规划是一种常用的算法思想,广泛应用于各类问题的求解中。而背包问题则是动态规划中最经典且常见的问题之一。背包问题涉及在给定容量的背包中选择物品以达到最优解的目标。本篇博客将专注于介绍和讨论与背包问题相关的动态规划算法。我们将探索不同类型的背包问题,并详细讲解其动态规划的解决思路。
题目:01背包问题 LeetCode 416
题目概述:01背包问题是最基础的背包问题之一。给定一组物品,每个物品有重量和价值,背包具有一定的容量,需要在不超过背包容量的前提下,选择物品使得总价值最大化。
题解:使用动态规划求解,定义dp[i][j]表示前i个物品放入容量为j的背包中所能达到的最大价值。状态转移方程如下:dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]),其中w[i]表示第i个物品的重量,v[i]表示第i个物品的价值。
def knapsack01(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 weights[i - 1] <= j:
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]
题目:完全背包问题 - LeetCode 322
题解:完全背包问题是一个经典的背包问题。给定一组面额不同的硬币和一个总金额,求出能够凑成总金额所需的最少硬币数量。使用动态规划求解,定义dp[i]表示凑成金额i所需的最少硬币数量。状态转移方程如下:dp[i] = min(dp[i], dp[i-coin] + 1),其中coin表示硬币的面额。 核心代码段:
def coinChange(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for coin in coins:
for i in range(coin, amount + 1):
dp[i] = min(dp[i], dp[i - coin] + 1)
return dp[amount] if dp[amount] != float('inf') else -1
题目:多重背包问题 - LeetCode 879
题解:多重背包问题是背包问题的一种扩展形式,每个物品有数量限制。给定一组工作,每个工作有所需的成本和利润,求出在不超过预算的前提下,能够获得的最大利润。使用动态规划求解,定义dp[i][j]表示前i个工作在预算不超过j的情况下所能达到的最大利润。状态转移方程如下:dp[i][j] = dp[i-1][j] + dp[i-1][j-cost],其中cost表示第i个工作的成本。 核心代码段:
def profitableSchemes(n, minProfit, group, profit):
m = len(group)
MOD = 10 ** 9 + 7
dp = [[0] * (minProfit + 1) for _ in range(n + 1)]
dp[0][0] = 1
for i in range(1, m + 1):
currGroup, currProfit = group[i - 1], profit[i - 1]
for j in range(n, currGroup - 1, -1):
for k in range(minProfit, -1, -1):
dp[j][k] +&