动态规划经典优化问题
0/1背包问题是一个经典的组合优化问题:给定n个物品(每个有重量和价值)和一个容量为W的背包,如何选择物品使得总价值最大,同时不超过背包容量?
设 dp[i][w] 表示考虑前i个物品、容量为w时的最大价值。
| 指标 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(N × W) | N是物品数,W是容量 |
| 空间复杂度 | O(N × W) | 存储DP表格 |
| 优化空间 | O(W) | 使用一维数组,逆序遍历 |
注意:这是伪多项式时间,因为W可能很大。当W以二进制表示时,算法是指数级的。
def knapsack_01(weights, values, capacity): """0/1背包问题 - 二维DP""" n = len(weights) dp = [[0] * (capacity + 1) for _ in range(n + 1)] for i in range(1, n + 1): for w in range(capacity + 1): # 不选第i个物品 dp[i][w] = dp[i - 1][w] # 选第i个物品 if w >= weights[i - 1]: dp[i][w] = max(dp[i][w], dp[i - 1][w - weights[i - 1]] + values[i - 1]) return dp[n][capacity] def knapsack_01_optimized(weights, values, capacity): """0/1背包问题 - 空间优化O(W)""" dp = [0] * (capacity + 1) for i in range(len(weights)): # 逆序遍历,保证每个物品只使用一次 for w in range(capacity, weights[i] - 1, -1): dp[w] = max(dp[w], dp[w - weights[i]] + values[i]) return dp[capacity] # 使用示例 weights = [2, 3, 4, 5] values = [3, 4, 5, 6] capacity = 8 print(knapsack_01(weights, values, capacity)) # 10
public class Knapsack { /** * 0/1背包问题 - 二维DP */ public static int knapsack01( int[] weights, int[] values, int capacity) { int n = weights.length; int[][] dp = new int[n + 1][capacity + 1]; for (int i = 1; i <= n; i++) { for (int w = 0; w <= capacity; w++) { // 不选第i个物品 dp[i][w] = dp[i - 1][w]; // 选第i个物品 if (w >= weights[i - 1]) { dp[i][w] = Math.max(dp[i][w], dp[i - 1][w - weights[i - 1]] + values[i - 1]); } } } return dp[n][capacity]; } /** * 0/1背包问题 - 空间优化O(W) */ public static int knapsack01Optimized( int[] weights, int[] values, int capacity) { int[] dp = new int[capacity + 1]; for (int i = 0; i < weights.length; i++) { // 逆序遍历 for (int w = capacity; w >= weights[i]; w--) { dp[w] = Math.max(dp[w], dp[w - weights[i]] + values[i]); } } return dp[capacity]; } public static void main(String[] args) { int[] weights = {2, 3, 4, 5}; int[] values = {3, 4, 5, 6}; System.out.println(knapsack01(weights, values, 8)); // 10 } }