跳转至

ch6 递推与动态规划

1. 递推

递推流程:

  1. 设定递推初值。
  2. 依公式递推,常用循环实现。

递推优点:

  • 递推公式往往比通项公式容易得到。
  • 计算机非常擅长递推公式的重复计算。

2. 动态规划

  1. 把问题分解为多个阶段:

    • 每个阶段面临的都是与原问题相似的子问题。
    • 子问题的最优解能够累积得到整体最优解,或者说整体最优解的每个阶段都是子问题的最优解(最优性原理)。
  2. 找出每个阶段下的多个状态:

    • 考虑每个状态下有哪些可选的决策。
    • 找出每个状态下的最优决策。
    • 写出最优决策下状态转移的递推公式。
    • 考虑递推的方向,并由此确定递推初始值。
    • 考虑如何记录最优决策,以便输出整体最优解。

3. 最长公共子序列

  1. 把问题分解为多个阶段:

    逐个字母依次比较,是自然的阶段划分。

    • 每个阶段面临的都是与原问题相似的子问题:

      显然,子问题是 “求缩短后序列的最长公共子序列”。

    • 最优性原理:

      如果首字母相同,我们的策略能够保证累积得到一个整体最优解。如果首字母不同,不会丢失整体最优解。

  2. 找出每个阶段下的多个状态:

    只有 \(1\) 个状态:求 \(\tt A[i,m)\)\(\tt B[j,n)\) 的最长公共子序列。

    • 考虑每个状态下有哪些可选的决策:

      我们只考虑了一种 “不会亏” 的决策。

    • 找出每个状态下的最优决策:

      “不会亏” 的决策是一种最优决策。

      \(\tt A[i]=B[j]\) 时,\(\tt A[i](B[j])\) 加入公共子序列;

      \(\tt A[i]\ne B[j]\) 时,抛弃 \(\tt B[j]\)\(\tt A[i]\),取两者中较优的。

    • 写出最优决策下状态转移的递推公式:

      \(\tt lcs(i,j) = \begin{cases} \tt 1 + lcs(i+1, j+1), & \tt if(A[i] = B[j]) \\ \tt max\{lcs(i, j+1), lcs(i+1, j)\}, & \tt if (A[i] \ne B[j]) \end{cases}\)

    • 考虑递推的方向,并由此确定递推初始值。

      计算 \(\tt lcs[i,j]\) 需要 \(\tt lcs[i+1,j+1],\ lcs[i+1,j],\ lcs[i,j+1]\),因此递推从较大的下标开始逆推。于是递推初值为 \(\tt lcs\) 数组的第 \(n\) 行和第 \(m\) 列的值为 \(0\)