动态规划

本文介绍了动态规划的基本要素,包括最优子结构性质和重叠子问题,并详细阐述了动态规划算法的四个基本步骤。以最长公共子序列问题为例,分析了问题定义、结构特征和解题思路,通过递归结构展示了如何计算最优值并构造最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1. 动态规划问题的基本要素

(1)最优子结构性质

  当问题的最优解包含了子问题的最优解时,我们称问题具有最优子结构性质。
  在动态规划算法中,利用问题的最优子结构性质,以自底向上的方式递归的从子问题的最优解逐步构造出整个问题的最优解。

(2)重叠子问题

  动态规划问题利用了子问题的重叠性质,对每一个子问题只求解一次,然后保存到一个表格中,当再次需要解此问题时,知识简单的用常数时间查看一下结果。

2. 动态规划算法的基本步骤

  (1)找出最优子结构性质,并刻画其结构特征
  (2)递归地定义最优值
  (3)以自底向上的方式计算最优值
  (4)根据计算最优值时得到的信息构造最优解

3. 动态规划问题举例-最长公共子序列问题

问题定义

  给定两个序列X={x1,x2,….,xm}和Y={y1,y2,….,yn},当另一序列Z既是X的子序列有事Y的子序列时,称Z是序列X和Y的公共子序列。
最长公共子序列问题:给定两个序列X和Y,找出X和Y的最长公共子序列。

最长公共子序列的结构

  最长公共子序列问题具有最优子结构性质。
  设序列X={x1,x2,….,xm}和Y={y1,y2,….,yn}的最长公共子序列为Z={z1,z2,….,zk},则
  (1)若xm=yn,则zk=xm=yn,且Zk-1是Xm-1和Yn-1的最长公共子序列
  (2)若xm!=yn且zxk!=xm,则Z是Xm-1和Y的最长公共子序列
  (3)若xm!=yn且zxk!=yn,则Z是X和Yn-1的最长公共子序列

子问题的递归结构

  首先要建立子问题最优值的递归关系。用c[i][j]记录序列Xi和Yj的最长公共子序列的长度。其中Xi={x1,x2,….,xi};Yj={
y1,y2,….yj}。当i = 0或j = 0时,空序列是Xi和Yj的最长公共子序列,故此时c[i][j] = 0。在其他情况下,最优子结构性质可建立如下的关系
c[i][j] = 0            i = 0, j = 0
   =c[i - 1][j - 1] + 1     i, j > 0; xi = yj
   =max{c[i][j - 1], c[i - 1][j]}  i , j > 0; xi != yj

计算最优值

  计算最长公共子序列的动态规划算法LCSLength以序列X={x1,x2,….,xm}和Y={y1,y2,….,yn}作为输入,输出两个数组c和b。其中c[i][j]存储Xi和Yjde最长公共子序列的长度,b[i][j]记录c[i][j]的值是由哪一个子问题的解得到的,这在构造最长公共子序列时会用到。

void LCSLength(int m, int n, char *x, char *y, int **c, int **y){
    int i, j;
    for (i = 0; i < m; i++) c[i][0] = 0;
    for (j = 0; j < n; j++) c[0][j] = 0;
    for (i = 0; i < m; i++){
        for (j = 0; j < n; j++){
            if (x[i] == y[j]){
                c[i][j] = c[i-1][j-1] + 1;
                b[i][j] = 1;
            }else if (c[i-1][j] >= c[i][j-1]){
                c[i][j] = c[i-1][j];
                b[i][j] = 2;
            }else{
                c[i][j] = c[i][j-1];
                b[i][j] = 3;
            }
        }
    }
}

构造最长公共子序列

  由算法LCSLength计算得到的数组b可用于快速构造序列X={x1,x2,….xm}和Y={y1,y2,….yn}的最长公共子序列。首先从b[m][n]开始,根据值在b中搜索。当b[i][j] = 1时,表示Xi和Yj的最长公共子序列是由Xi-1和Yj-1的最长公共子序列在尾部加上xi所得到的。当b[i][j] = 2时,表示Xi和Yj的最长公共子序列与Xi-1和Yj的最长公共子序列相同。当b[i][j] = 3时,表示Xi和Yj的最长公共子序列与Xi和Yj-1的最长公共子序列相同。
  算法LCS实现根据b的内容打印输出X和Y的最长公共子序列。

void LCS (int i, int j, char *x, char *b){
    if (i == 0 || j == 0) return;
    if (b[i][j] == 1){
        LCS(i - 1, j - 1, x, b);
        cout << x[i];
    }else if (b[i][j] == 1){
        LCS(i - 1, j , x, b);
    }else{
        LCS(i, j - 1, x, b);    
    }
}

参考文献

王晓东. 《计算机算法设计与分析(第四版)》. 电子工业出版社. 44-54

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值