算法设计与分析.06.动态规划 (1)

动态规划

  • DP:Dynamic Programming

DP

  • 贪心:短视的做出有利的决定
  • 分治:划分为独立的子问题,解决后进行归并
  • 动规:分解为可交叉的子问题,汇总子问题的方案

典型算法

  • Avidan–Shamir for seam carving.
  • Unix diff for comparing two files.
  • Viterbi for hidden Markov models.
  • De Boor for evaluating spline curves.
  • Bellman–Ford–Moore for shortest path.
  • Knuth–Plass for word wrapping text in \(\TeX\).
  • Cocke–Kasami–Younger for parsing context-free grammars.
  • Needleman–Wunsch/Smith–Waterman for sequence alignment.

weighted interval scheduling

  • 任务 \(j\),开始时间 \(s_j\),结束时间 \(f_j\),权重 \(w_j>0\)
  • 求最大权重和的相容的任务集合

思考

  • 贪心:先按照(开始时间,结束时间)排序
    • 权重为 1 是正确的
    • 权重不为 1 是不正确的

DP

  • 按照(结束时间)排序
  • \(p(j)\):满足和任务 \(j\) 相容的最大的 \(i\)
  • \(OPT(j)\):前 \(j\) 个任务的子问题
  • 原始问题,求 \(OPT(n)\)
  • 转移方程
    • 选不选任务 \(j\)

\[ OPT(j)=\max\{OPT(j-1),OPT(p(j))+w_j\} \]

  • \(p(j)+1,\cdots,j-1\) 都和任务 \(j\) 不相容

复杂度

  • 排序:\(n\log n\)
  • 计算 \(p(j)\),二分:\(n\log n\)
  • DP:\(O(n)\)
    • 每一个子问题只需要计算一次

实现

Top-Down

  • 如果递归的方式实现,需要使用记忆化搜索(有很多相同的子问题)

恢复
  • 下面这个算法本质上是在寻找,DP 的时候进入的是哪一个分支

Bottom-Up

maximun subarray problem

  • 给定一个数组,数组元素有正有负,找到连续的和最大的子数组

思考

  • 枚举
    • \(O(n^3)\)
1
2
3
4
5
6
7
8
9
10
int ans = 0;
for (int i = 0; i < length; ++i) {
for (int j = i; j < length; ++j) {
int s = 0;
for (int k = i; k <= j; ++k) {
s += a[k];
}
ans = max(s, ans);
}
}
  • 预处理,\(sum[i]\) 表示 \(a[0],a[1],\cdots,a[i]\) 的和
    • \(O(n^2)\)
1
2
3
4
5
6
7
8
9
10
11
12
13
int accu = 0;
for (int i = 0; i < length; ++i) {
accu += a[i];
sum[i] = accu;
}

int ans = 0;
for (int i = 0; i < length; ++i) {
for (int j = i; j < length; ++j) {
int s = sum[j] - (i ? sum[i - 1] : 0);
ans = max(s, ans);
}
}

DP

  • \(O(n)\)
  • \(OPT(j)\):前 \(j\) 个元素中,以元素 \(a[j]\) 结尾的最大连续和
    • 下标从 1 开始
  • 原始问题:\(\max_i OPT(i)\)
  • 转移方程
    • 只选 \(a_i\),或者加上前面连续的最大值
    • \(OPT(1)=x_1\)

\[ OPT(j)=\max\{x_i,x_i+OPT(p(j))\} \]

maximum rectangle problem

  • 矩阵中找出和最大的一个矩形区域

  • 算法
    • 枚举 \(i,j\),表示 \([i,j]\) 列,对这些列的行求和得到数组 \(x\)
      • \(O(n)\)
    • 对数组 \(x\) 应用上面的 maximun subarray problem 算法
      • \(O(n)\)
    • \(n^2\cdot O(n)=O(n^3)\)
  • 计算 \(x\)
    • 预计算矩阵 \(S[i,j]\)
    • \(S[i,j]=\sum_{k=1}^{j}A[i.j]\)
    • 选中 \(i,j\),那么 \(x[k]=S[k,j]-S[k,i-1]-S[k-1,j]+S[k-1,j-1]\)

segmented least squares

Least squares

  • 平面上给定 \(n\) 个点,找到一条直线 \(y=ax+b\),使得如下误差最小
    • the sum of the squared error

  • 有数值解

问题

  • 分段 SSE,分段函数,每一段都是直线,找最小的 SSE

  • 最小化 \(f(x)=E+cL\)
    • \(E\):每一段的误差
    • \(L\):线段
    • \(c>0\):权重

DP

  • \(OPT(j)\):子问题 \(1,2,\cdots,j\)
  • \(e_{i,j}\)\(p_i,\cdots,p_j\) 的 SSE
  • 转移方程
    • 枚举最后一段折线的长度,然后转化为子问题
    • \(OPT(0)=0\)

\[ OPT(j)=\min_{1\le i\le j}\{e_{i,j}+c+OPT(i-1)\} \]

  • 计算 SSE
    • 预计算 4 个数组 a,b,c,d
      • \(\sum_{i}x_i,\sum_{i}y_i,\sum_{i}x_iy_i,\sum_{i}x_i^2\)
    • 每一个数组记录 \(\sum_{i=1}^{k}\)
    • 此时计算 SSE 为 \(O(1)\)
    • 例子

\[ a[k]=\sum_{i=1}^{k}x_i \]

  • 时间复杂度:\(O(n^2)\)

knapsack problem

  • 背包问题
    • 背包限重 \(W\)
    • 每一个物品有一个重量 \(w_i\) 和价值 \(v_i\)
    • 让装入背包的物品价值和最高
  • 假定权重为整数

DP

  • \(OPT(i,w)\):只装前 \(i\) 个物品,限重为 \(w\) 的最大价值
  • 原始问题:\(OPT(n,W)\)
  • 转移方程
    • 装不装当前物品

\[ OPT(i,w)=\max\{OPT(i-1,w),OPT(i-1,w-w_i)+v_i\} \]

\[ i<0\lor w<0\Rightarrow OPT(i,w)=-\infty \]

  • 恢复,类似于上面的算法,判断进入哪一个分支
    • \(M[i,w]>M[i-1,w]\),则选中了当前物体
  • 时间复杂度:\(O(nW)\)
    • 伪多项式时间
    • 物品编码数量:\(n\)
    • 重量 \(w\) 的编码:\(\log W\)
  • 空间复杂度:\(O(nW)\)

coin changing

  • n 种硬币 \(\{d_1,\cdots,d_n\}\),数量无限,使用最少的硬币实现和为 \(V\)
    • 贪心算法只对某些硬币种类有效

DP

  • \(OPT(v)\):实现和为 \(v\) 的最小硬币数
  • 原始问题:\(OPT(V)\)
  • 转移方程
    • 枚举不同种类的硬币
    • \(OPT(0)=0\)
    • \(v\le 0\Rightarrow OPT(v)=\infty\)

\[ OPT(v)=\min_{1\le i\le n}\{1+OPT(v-d_i)\} \]

  • 时间复杂度:\(O(nV)\)

RNA secondary structure

  • 配对规则
    • A-U
    • C-G

RNA 二级结构

  • 满足配对原则
  • No Sharp turns
    • 配对中间至少存在 4 个间隔
    • 下图不行,只隔了 3 个碱基

  • No Crossing
    • 配对不能交叉
    • 下图不行,交叉了

  • 最小能量:配对的数量越多,能量越低

DP

  • \(OPT(i,j)\)\(b_i\cdots b_j\) 的最大配对数
  • 原始问题:\(OPT(1,n)\)
  • 转移方程
    • \(i\ge j-4\Rightarrow OPT(i,j)=0\)
    • \(b_j\) 是否配对
    • \(b_j\)\(b_t\) 满足配对原则

\[ \begin{aligned} OPT(i,j)=\max\{&\\ &OPT(i,j-1),\\ &1+\max_{i\le t<j-4}\{OPT(i,t-1)+OPT(t+1,j-1)\}\\ \}&\\ \end{aligned} \]

  • 实现:按照区间长度从短到长进行循环

  • 时间复杂度:\(O(n^3)\)
  • 空间复杂度:\(O(n^2)\)

DP 总结

  • Techniques.
    • Binary choice:weighted interval scheduling
      • 选不选
    • Multiway choice:segmented least squares
      • 选哪个
    • Adding a new variable:knapsack problem
      • 增加一个维度
    • Intervals:RNA secondary structure
      • 区间长度