📐 组合优化 · 动态规划

最优子结构 · 重叠子问题 · 背包 · Held-Karp · 序列对齐
🎒 0-1背包 🗺️ TSP Held-Karp 🧬 序列对齐 ⚡ 最优子结构
🧩 最优子结构 & 重叠子问题 DP 两大支柱

🔺 最优子结构

问题的最优解包含子问题的最优解。例如:

  • 最短路径:子路径也是最短。
  • 背包问题:前i件物品在容量c下的最优值。
  • 序列对齐:前缀对齐得分最优。
📌 形式化: 若 OPT 分解为 OPT(sub1) + cost,则子决策必优。

🔁 重叠子问题

递归求解时反复出现相同子问题,DP通过记忆化避免重复计算。

  • 斐波那契:大量重复 fib(n-2)。
  • 背包:子问题 (i, c) 被多次引用。
  • Held-Karp:子集状态复用。
📊 对比分治: 分治子问题独立,DP子问题重叠。
🎒 背包问题 DP 解法 0-1 背包 & 完全背包

📦 0-1 背包

dp[i][c] = max(dp[i-1][c], dp[i-1][c-w_i] + v_i)

# Python 简洁实现 (空间优化)
def knapsack_01(weights, values, capacity):
    n = len(weights)
    dp = [0] * (capacity + 1)
    for i in range(n):
        for c in range(capacity, weights[i]-1, -1):
            dp[c] = max(dp[c], dp[c-weights[i]] + values[i])
    return dp[capacity]

⏱ O(n·C) 空间 O(C)

♾️ 完全背包

dp[c] = max(dp[c], dp[c-w_i] + v_i) (正序遍历)

# 完全背包 (Python)
def unbounded_knapsack(weights, values, capacity):
    dp = [0] * (capacity + 1)
    for i in range(len(weights)):
        for c in range(weights[i], capacity+1):
            dp[c] = max(dp[c], dp[c-weights[i]] + values[i])
    return dp[capacity]

♻️ 物品无限,正序更新

🗺️ 旅行商问题 · Held-Karp 算法 DP over subsets

🧠 状态定义 & 递推

状态: dp[mask][v] 表示从起点0出发,经过集合 mask 中的城市,最后到达城市 v 的最短路径长度。

递推:

dp[mask][v] = min(
    dp[mask\{v}][u] + dist[u][v] 
    for u in mask\{v}
)

初始化 dp[1<<0][0] = 0,最终答案 min(dp[(1<

⏱ O(n²·2ⁿ) 空间 O(n·2ⁿ)

📐 子集可视化 (n=4)

0 1 2 3 mask=1011

子集 {0,1,3} 状态示例

🧬 DP 在序列对齐中的应用 全局对齐 · 编辑距离

🧪 递推矩阵

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

# 全局对齐 (简化)
def align(x, y, match=2, gap=-1):
    n, m = len(x), len(y)
    dp = [[0]*(m+1) for _ in range(n+1)]
    for i in range(n+1): dp[i][0] = i * gap
    for j in range(m+1): dp[0][j] = j * gap
    for i in range(1, n+1):
        for j in range(1, m+1):
            score = match if x[i-1]==y[j-1] else -1
            dp[i][j] = max(dp[i-1][j-1]+score,
                           dp[i-1][j]+gap, dp[i][j-1]+gap)
    return dp[n][m]

📊 对齐示例表

_AGC
_0-1-2-3
A-1210
C-2113

🔹 回溯可得最优对齐:A-C 与 AGC 的比对

⏱ O(n·m) 空间 O(n·m) / 可优化至 O(min(n,m))

⚙️ DP 算法架构总览 动态规划核心流程
问题分解 最优子结构 状态定义 dp[...] 递推方程 重叠子问题 解 记忆化 / 表格填表 · 自底向上 / 自顶向下 背包 · TSP · 序列对齐 均遵循此范式
📋 经典DP问题对比
问题状态维度递推特点时间复杂度空间优化
0-1背包dp[i][c]逆序容量O(n·C)滚动数组 O(C)
完全背包dp[c]正序容量O(n·C)O(C)
TSP (Held-Karp)dp[mask][v]子集枚举O(n²·2ⁿ)O(n·2ⁿ)
序列对齐dp[i][j]三种转移O(n·m)O(min(n,m))