南开大学软件学院2021年秋季学期研究生算法课程(复习)动态规划

动态规划

数字三角形

如上图所示,请找出一条自顶向下路径,使得该路径上所有数字的和最大

  • 如何定义状态?第i行第j个数
  • 如何进行搜索?DFS枚举所有路径即可(回溯法
  • 时间复杂度?若共有n层,时间复杂度O(2^n)

是否可以减少不必要的搜索(规避不必要的状态转移)了呢?

  • 注意第3行第2个数
  • 价值函数定义恰当,则只需搜过一次即可:记忆化搜索

动态规划Dynamic programming,DP

在搜索过程中,对于已经搜索过、且价值函数不会再度更新(或变优)的状态,则可以通过记忆化的方式,规避重复搜索

因此,才有动态规划算法适用问题所具备的必要条件

  • 最优子结构:最优解可以由子问题的最优解(或部分状态的最优价值函数)构造得出
  • 重叠子问题:一些子问题(或状态)在搜索中会重复遇到
  • 无后效性:子问题最优解一旦确定就不会再被更新
    • 该性质可以直接否定某些问题使用动态规划的可行性。其实,此性质暗示了动态规划可解问题的状态空间一般都是有向无环图

动态规划的宏观理解

本质就是状态空间中的一种“聪明的”搜索策略,因此

  • 依然需要恰当准确的状态空间建模
  • 重点在于状态的价值函数的设计(通常为优化目标函数
  • 同时,状态转移过程中的价值函数更新方式也很关键

关键点

动态规划算法解决问题的难点不仅是能否准确地、用尽可能少的状态变量(或称为维度)对问题建模,还要设计合理的价值函数(甚至赋予特殊意义),并准确地给出价值函数在状态转移过程中的更新方式

鉴于以上,才可以总结出动态规划算法设计的三个关键环节

  1. 定义状态和价值函数(建模
  2. 确定初始状态和对应价值(边界
  3. 确定状态转移中的价值更新方式(状态转移方程

动态规划两种实现

记忆化搜索Memorization

自顶向下(top-down)的实现(DP的本质:暴力搜索优化)

  • 状态:递归函数的参数形式
  • 状态转移:函数调用,通过实际传入参数
  • 价值函数:函数的返回值,须记录(数组或字典)

打表法Tabulation

自底向上(bottom-up)的实现(动态规划的常见方案)

  • 状态:数组的下标
  • 状态转移:数组元素间的递推关系
  • 价值函数:数组的

所以如何游刃有余地掌握动态规划算法?积累模型

类型Ⅰ:一维递推问题(求和形式)

爬楼梯

一个由n级台阶的楼梯,每步可以迈1、2、3级,问爬完这段楼梯有几种不同的方式?

  • 如何定义状态和价值函数?f(i)表示走到第i级台阶的种类数
  • 状态转移方程?f(i)=f(i-1)+f(i-2)+f(i-3)
  • 边界与答案?边界f(1)=1,f(2)=2,f(3)=4,答案为f(n)
  • 时间复杂度?O(n)

优化方式

矩阵快速幂优化f(i)=\sum_{t=1}^k g(t)f(i-t),O(log n)

类型Ⅱ:一维递推问题(最值形式)

  • 最长上升子序列Longest increasing sequence,LIS

给一个数组,请找出这个数组中的一个最长的单调递增子序列(可以不连续)

  • 如何定义状态和价值函数?f(i)为第i个数作为结尾的最长上升子序列的长度
  • 状态转移方程?f(i)=max_{1\leq j\leq i}\left \{ I(a_i>a_j)f(j)+1 \right \}
  • 边界与答案?f(i)=0,答案为max_{1\leq i\leq n}\left \{ f(i) \right \}
  • 时间复杂度?O(n^2)

优化方式

  • 单调队列/栈优化 Monotonic queue/stackf(i)=min_{i-k\leq j\leq i}\left \{ f(j) \right \}+g(i)
  • 斜率优化 Convex hull trickf(i)=min_{1\leq j\leq i}\left \{ g(j)+b(j)\times a(i) \right \}+w(i)

类型Ⅲ:二维问题----区间问题

最长回文子序列Longest Palindromic Subsequence

回文指形如:“ABBA”,“CDC”等正反一样的序列,给出任意序列,计算最长回文子序列长度。(如“GOODGAME”的答案“GOOG”)

  • 如何定义状态和价值函数?f(i,j)表示区间i,j之间的最长回文子序列长度
  • 状态转移方程?f(i,j)=max\left \{ f(i+1,j),f(i,j-1),f(i+1,j-1)+2\delta (s_i==s_j) \right \}
  • 边界与答案?f(i,i)=1,答案f(1,n)
  • 时间复杂度?O(n^2)

回文子序列的个数Couting Palindromic Subsequences

求字符串中回文子序列的个数。(如CDC的回文子序列包括C,D,C,CC,CDC,共5个,位置不同的相同序列需要重复计数

  • 如何定义状态和价值函数?f(i,j)表示区间i,j之间的最长回文子序列个数
  • 状态转移方程?f(i,j)=f(i+1,j)+f(i,j-1)-\delta(s_i\neq s_j)f(i+1,j-1)+\delta(s_i=s_j)
  • 边界与答案?f(i,i)=1,答案f(1,n)
  • 时间复杂度?O(n^2)

最优矩阵链乘法

n个矩阵连续相乘,第i个矩阵的维度为r_i\times c_i,问如何通过加括号的方式最快完成矩阵乘法?

  • 如何定义状态和价值函数?f(i,j)i,j间的最快方案
  • 状态转移方程?f(i,j)=min_{i\leq k\leq j}\left \{ f(i,k)+f(k+1,j)+r_ic_kc_j \right \},c_k=r_{k+1}
  • 边界与答案?f(i,i)=0,答案f(1,n)
  • 时间复杂度?O(n^3)

优化方式

四边形不等式优化Knuth optimization

f(i,j)=min_{i\leq k\leq j}\left \{ f(i,k-1)+f(k,j)+w(i,j) \right \}

区间最值查询Range Minimum/Maximum Query,RMQ

给出长度为n的数组和m次询问,每次询问要求l,r区间内最值

  • 如何定义状态和价值函数?f(i,j)为以i为起点,长度为2^j的区间最值(倍增思想)
  • 状态转移方程?f(i,j)=min\left \{ f(i,j-1),f(i+2^{j-1},j-1) \right \}
  • 边界与答案?f(i,0)=a_i,令s=\left \lfloor \log(r-l+1) \right \rfloor,答案为\min\left \{ f(l,s),f(r-2^s+1,s) \right \}
  • 时间复杂度?O(n logn + m)

类型Ⅳ:二维问题----序列间比较问题

编辑距离Edit distance

给出字符串A和B,对A进行三种操作:插入、删除或替换一个字符,问由A修改为B最少要几步?

  • 如何定义状态和价值函数?f(i,j)为使A长度为i的前缀与B长度为j的前缀通过编辑实现匹配的最少次数
  • 状态转移方程?f(i,j)=\min \left \{ f(i-1,j)+1,f(i,j-1)+1,f(i-1,j-1)+\delta(A_i\neq B_j) \right \}
  • 边界与答案?f(0,i)=i,f(j,0)=j,答案f(l_A,l_B)
  • 时间复杂度?O(n^2)

类型Ⅴ:树与图上的问题

快乐聚会

某公司中有明确的上下属关系,可以用有根树表示。现举办聚会,每个人都有一个快乐指数a_i,但是如果一个人的上属参加了聚会,那么此人就不会参加,求聚会最大快乐指数和?

  • 如何定义状态函数和价值函数?f(x,1/0)表示员工x参加/不参加聚会时其与其下属的最大快乐指数之和
  • 状态转移方程?f(x,0)=\sum_{y\in S(x)}max\left \{ f(x,0),f(x,1) \right \}f(x,1)=a_x+\sum_{y\in S(x)}f(x,0)
  • 边界与答案?f(leaf,0)=0,f(leaf,1)=a_x,答案为\max \left \{ f(root,0),f(root,1) \right \}
  • 时间复杂度?O(n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值