动态规划设计要素

1. 设计要素

  1. 问题建模,优化的目标函数是什么?约束条件是什么?
  2. 如何划分子问题 (边界) ?
  3. 问题的优化函数值与子问题的优化函数值存在 着什么依赖关系?(递推方程)
  4. 是否满足优化原则?
  5. 最小子问题怎样界定?其优化函数值,即初值等于什么?

2. 具体例子:矩阵链相乘

2.1 问题:

  • A1,A2,… ,An 为矩阵序列 (就是一共有n个矩阵)
  • Ai为Pi-1×Pi阶矩阵,i = 1,2,… ,n.
    (这就确定了相邻的矩阵可以相乘)
  • 试确定矩阵的乘法顺序,使元素相乘的总次数最少

输入:
向量 P = <P0,P1,…,Pn>
其中P0,P1,… ,Pn为n个矩阵的行数和列数

  • 例如:
    P = <10,100,5,50>
    A1:10×100,A2:100×5,A3:5×50

输出:
矩阵链乘法加括号的位置

2.1.1 两个矩阵元素相乘的次数

在这里插入图片描述

  • 先算一个元素的次数:
    cts = at1b1s + at2b2s + … + atjbjs
    计算一个元素共 j 次乘法
  • 结果共有 i 行,k
    ij 列 × jk 列 = ik

共需乘法次数:ijk

2.1.2 实例

P = <10,100,5,50>
A1:10×100,A2:100×5,A3:5×50
乘法次序

  • (A1A2)A3:10 × 100 × 5 + 10 × 5 × 50 = 7500
  • A1(A2A3): 100 × 5 × 50 + 10 × 100 × 50 = 75000

第一种次序计算次数最少

2.2 蛮力算法

  • 如果是 m 个矩阵相乘,那么一共需要加 m - 1 对括号
    • 加括号是为了确定运算顺序,如果是两个数,自然只需要确定一个运算顺序,如果是确定三个数的运算顺序,就要确定两个运算顺序,即哪两个数相乘,然后前面两个数相乘得到的结果再与最后一个数相乘,即加两个括号
  • n 个括号的方法有 1 n + 1 1\over{n + 1} n+11C2nn
    • 如两个括号()()、(())
    • 三个括号((()))、()(())、(())()、(()())、()()()

在这里插入图片描述

蛮力算法通过穷举所有可能的括号化方式并计算它们的成本,然后选择最小成本的方式

2.3 动态规划算法

2.3.1 算法思想

2.3.1.1 子问题划分
  • 先给出一个概念
    Ai…j:矩阵链AiAi+1…Aj,边界i,j
  • 输入向量:<Pi-1,Pi,…,Pj>
  • 设其最好划分的运算次数:m[i,j]
2.3.1.2 子问题的依赖关系

最优划分最后一次相乘发生在矩阵 k 的位置
Ai…j = Ai…k Ak+1…j
那么Ai…j 的最优运算次数依赖于Ai…kAk+1…j最优运算次数

2.3.1.3 优化函数的递推方程

m[i,j]:得到Ai…j的最少的相乘次数
在这里插入图片描述
在这里插入图片描述
且满足优化原则(当子问题更优化时原问题也更优化)

2.3.2 递归算法

2.3.2.1 递归思想

在这里插入图片描述

  • k循环,找到通过递归的方法找到一个最好的k
  • 在循环的时候,如果找到一个更好的,那就替代原先的
  • 这里是递归的求解m中的值的,m的值要通过RecurMatrixChain这个函数求得 (所以叫递归),(与下面的方法不同)
2.3.2.2 时间复杂度

在这里插入图片描述
在这里插入图片描述

2.3.3 迭代实现

2.3.3.1 递归算法子问题的产生

比如当 n = 5 时
在这里插入图片描述

  • 第一次循环会产生 8 个子问题,然后每个子问题再递归产生更多子问题
  • 但有些子问题会重复出现多次 (比如划分为1-1的这个子问题出现好多次,在图中看颜色区分就行)

子问题计数
在这里插入图片描述

  • 边界不同的子问题:15个
  • 递归计算的子问题总个数:81个
2.3.3.2 迭代计算关键
  • 每个子问题只计算一次
  • 迭代过程
    • 考虑计算的顺序,以保证后面用到的值前面已经计算好
    • 存储结构保存计算结果——备忘录
  • 解的追踪 (我们最终的结果是要算最少的乘法次数,因此要追踪计算每次乘法的次数)
    • 设计标记函数标记每步的决策
    • 考虑根据标记函数追踪解的算法
2.3.3.3 矩阵链乘法子问题计算顺序
  • 共有n个含1个矩阵(长度为1)的子问题
  • 共有n - 1个含2个矩阵(长度为2)的子问题
  • 共有n - 2个含3个矩阵(长度为3)的子问题
  • 共有2个含n - 1个矩阵(长度为n - 1)的子问题
  • 共有1个含n个矩阵(长度为n)的问题(即原始问题)
    在这里插入图片描述
  • 假设我们就规定子问题的求解顺序为上图的顺序
2.3.3.3.1 计算顺序实例

在这里插入图片描述

2.3.3.4 迭代实现伪码

在这里插入图片描述
步骤详解

  • 1 当只有1个矩阵的时候,运算次数为0次,且保证后面m值的计算都可以用前面的m的值来算,而不是递归的调用函数来求的,后面举个例子来说明
  • 2-4 为了能够实现先算链长较小的子问题
  • 5-6 计算此时还没划分的时候的乘法次数k的位置,也算是给m的值先算出来一个初值,方便后面比较大小看哪种情况算出来的m的值最小
  • 7-11 同上面递归的算法一样,划分k,并且找出最少的划分次数和此时对应的k
2.3.3.5 时间复杂度

根据伪码

  • 2,3,7都是O(n)
  • 循环执行O(n3) 次,内部为 O(1)
  • W(n) = O(n3)
2.3.3.6 实例

在这里插入图片描述

2.3.3.6.1 实例的备忘录m[i,j]

在这里插入图片描述

  1. r = 1,我们赋初值全部为 0
  2. r = 2,m[1,2] = m[2,2] + 30 × 35 × 15 = 15750 ,本来后面还有对k的划分,但是r太小了,所以这里没写,其他r = 2的值同理
  3. r = 4,(此时 r = 3、r = 2等等这些m的值都已经算出来了) 比如 m[2,5] 的值为7125,计算过程为:
    • 可以看作 m[2,2]m[3,5] 这两个子问题相乘
      在这里插入图片描述
      在这里插入图片描述
      此时结果为:0 + 2500 + 35 × 15 × 20 = 13000

    • 也可以看作 m[2,3]m[4,5] 两个子问题
      在这里插入图片描述
      在这里插入图片描述
      结果为 2625 + 1000 + 35 × 5 × 20 = 7125

    • 在这里插入图片描述
      在这里插入图片描述
      结果为 4375 + 0 + 35 × 10 × 20 = 11375

因此结果为7125

2.3.3.6.2 实例的标记函数s[i,j]
  • 用来记录在当前位置最佳的划分位置(即k的位置)
    在这里插入图片描述
    怎么通过这个图来找到最佳的
  1. 先从r = 5分析
    在这里插入图片描述
  2. 由1可以看出我们把原问题转化为s[1,3]和s[4,5],于是找s[1,3]和s[4,5]
    在这里插入图片描述
    在这里插入图片描述
    因此总的结果为
    在这里插入图片描述
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值