动态规划浅析

一、简述

动态规划是一种功能非常强大的计算模式,其解决问题的方式是首先定义它的一组子问题,然后按照由小到大,以小问题的解答支持大问题求解的模式,依此解决所有的子问题,并最终得到原问题(最大子问题)的解答

 二、最长递增子序列(Longest Increasing Sequence)
1 .问题描述:输入是一个数字序列a_{1},a_{2},a_{3},...,a_{n}, 所谓子序列,是指在以上序列中按顺序选出的一个子集,形如a_{i_{1}},a_{i_{2}},a_{i_{3}},...a_{i_{n}},其中1 \leq i_{1} < i_{2} < ... < i_{k} \leq n.如果子序列中的数字都是严格单调递增的,则称其为一个递增子序列。目标是找出原序列的一个最长子序列。
2.  解决思路:

  1. 为了更好地理解该问题的解空间,我们可以对任意两个可能在某递增子序列中存在递进关系的元素a_{i}a_{j},(即同时满足a_{i} < a_{j}i < j),增加一条连接二者对应节点的有向边,这样原问题就变成在DAG中找最长路径。
  2. L(j)是以j为终点的最长路径---对应着最长递增子序列的长度。可以看出,所有到达j的路径必然经过j的某个前驱节点,因此L(j)应该等于j所有前驱对应的最长递增子序列长度的最大值加1.而如果没有可以到达j的边,我们取L(j)为0.
    (存在子问题间的一种排序以及如下的关联关系:对于任意一个子问题这种关联关系说明了如何在给定相对其较小的子问题的解的前提下,求得该子问题的解)
  3. 状态转移方程:
    for j = 1,2...n:
        L(j) = 1 + max{L(i) : (i,j) belongs to E}
    return max{L(j)}

     

三、编辑距离(Edit distance)

1 . 问题描述:利用两个字符串能在多大程度上相互对齐得到两个字符串的距离。
2.  解决思路:

  1. 首先定义子问题:考虑这两个字符串的前缀(prefix)。可令E(n,m)为两个字符串x[1,...m]y[1,...n]之间的编辑距离。则前缀x[1,...i]y[1,...j]的编辑距离就可以表示为E(i,j)
  2. 接着考虑x[1,...i]y[1,...j]的最佳对齐,此时该对齐中最右侧的列只能是如下三种情况之一:
                                                             \begin{matrix} x[i]\\ - \end{matrix}     或    \begin{matrix} - \\ y[j] \end{matrix}     或          \begin{matrix} x[i]\\ y[j] \end{matrix}
    第一种情况:该列产生的情况是1,余下的是x[1,...i-1]y[1,...j]的距离问题,对应子问题E(i-1,j)
    第二种情况:同上,对应子问题E(i,j-1)
    第三种情况:如果x[i]\neq y[j],则代价为1,如果x[i] = y[j],则代价为0;剩下的子问题是E(i-1,j-1)
  3. 可得状态转移方程:
    E(i,j) = min\left \{ 1 + E(i-1,j),1+E(i,j-1),diff(i,j)+E(i-1,j-1) \right \}
    diff(i,j) = 0 当且仅当 x[i] = y[j]
  4. 求解算法
    for i =0,1,2...m:
        E(i,0) = i
    for j = 1,2,...m:
        E(0,j) = j
    for i = 1,2,..m:
        for j = 1,2,...n:
            E(i,j) = min{E(i-1,j)+1, E(i,j-1)+1 , E(i-1,j-1)+diff(i,j)}
    return E(m,n)

     

四、背包问题(Knapsack problem)
1. 问题描述:假设某人的背包最多能装W磅,一共n件物品,分别重w_{1},w_{2},...,w_{n},价值v_{1},v_{2},...v_{n}.怎样的组合才能使他带走的价值最高。
2. 多副本的背包问题:

  1. 子问题定义:考虑容量较小的背包,假设K(w)是容量w可以容纳的最高价值。
  2. 状态转移方程:K(w) =max\left \{ K(w - w_{i}) + v_{i} \right \}
  3. 算法:
    K(0) = 0
    for w = 1 to W:
        K(w) = max{K(w - wi) + vi : wi <= w}
    return K(w)

     

3. 单副本的背包问题:

  1. 子问题定义:单副本条件下不知道该物体有没有被使用过了,因此需要增加一个参数。K(w,j)是基于背包容量w和物品1,...j所能得到的最高价值,现在的目标是求K(w,n)
  2. 状态转移方程:要么需要选择物品j以获得最高价值,要么不需要。K(w,j) = max\left \{ K(w-w_{i},j-1)+v_{j},K(w,j-1) \right \}
  3. 算法:
    initialize all K(0,j) = 0 and all K(w,0)=0
    for j = 1 to n:
        for w = 1 to W:
            if wi > w:  K(w,j) = K(w,j-1)
            else: K(w,j) = max{K(w , j-1), K(w - wj, j-1) + vj}
    return K(W,n)

    算法需要填写一个二维的表格,其中共有W+1行和n+1列。填写这个表格仅需要常数时间。

 

五、矩阵链式相乘(Chain Matrix Multiple)
1. 问题描述:矩阵乘法次序不同会导致运行时间的巨大不同。假设我们需要计算A_{1} * A_{2} * ... * A_{n},其中每个矩阵的维数分别为m_{0}*m_{1},m_{1}*m_{2},...,m_{n-1}*m_{n},求最优的计算次序
2. 求解思路:

  1. 最优子问题:令C(i,j)是计算A_{i} * A_{i+1} * ... * A_{j}的最小代价
  2. 状态转移方程:C(i,j) = min\left\{ C(i,k) + C(k+1,j) + m_{i-1}*m_{k}*m_{j} \right\}
  3. 算法:
    for i = 1 to n:
        C(i,i) = 0
    for s = 1 to n-1:    //s代表子问题的规模
        for i = 1 to n-s:
            j = i + s
            C(i,j) = min{C(i,k) + C(k+1,j) + mi-1*mk*mj : i <= k < j}
    return C(1,n)
    

 

六、 最短路径问题(Short Path Problem)

1.  问题描述:求一个简单无向带权图中所有顶点的最短路径。---基于动态规划的Floyd-Warshall算法。
2.  求解思路:

  1. 最优子问题:记dist(i,j,k)为仅仅允许使用\left\{ 1,2,...,k \right\}作为中间节点时ij的最短路径长度。初始条件下,当存在直接连接ij的边时,dist(i,j,0)为该边的长度,否则为无穷
  2. 考虑当在中间节点集中加入一个新的顶点k时, 我们需要对所有的节点对ij检查是否使用k作为中间节点会得到更短的路径。ij的使用了k和其他编号较小中间节点的最短路径最多经过k一次,此时只需要将dist(i,k,k-1) + dist(k,j,k-1)dist(i,j,k-1)作比较,就能知道使用k是否能够在ij间得到一条更短的路径。

  3. 算法:
    for i = 1 to n:
        for j = 1 to n:
            dist(i,j,0) = MAX
    for all (i,j) belongs to E:
        dist(i,j,0) = arr[i][j]
    
    for k = 1 to n:
        for i = 1 to n:
            for j = 1 to n:
                dist(i,j,k) = min{dist(i,k,k-1)+dist(k,j,k-1) , dist(i,j,k-1)}

     

七、最长公共子串问题(Longest Common Sequence)
1. 问题描述:Given two sequences x[1..m] and y[1..n], find a(not the) longest subsequence common to them both. 
2. 解决思路:

  1. 最优子问题:考虑前缀C(i,j),它代表着串x[1,...,i]y[1,...,j]的最长公共子串的长度
  2. 状态转移方程:

  3. 算法:
    for i = 0 to m:
        C(i,0) = 0
    for j = 0 to n: 
        C(0,j) = 0    //DP一定要有基础条件
    
    if x[i] == y[j]:
        C(i,j) = C(i-1,j-1) + 1 
    else:
        C(i,j) = max{C(i-1,j),C(i,j-1)}

     

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值