动态规划算法设计

动态规划

1、问题建模;确定优化函数;约束条件

2、划分子问题

3、递推方程;也就是原问题的优化函数与子问题的优化函数存在的依赖关系;

4、是否满足组优化原则,也就是满足最优子结构性质

5、界定最小子问题,以及其优化函数初值等于什么;

如果采用递归的计算,相同子问题很有可能会计算多次,导致复杂度任然不低;要降低复杂度,需要保证每个相同的子问题只计算一次

6、从最小子问题算起,明确计算顺序,保证后面用到的值已经算好

7、保存子问题的计算结果–备忘录

8、是否需要设计标记函数

9、追踪解;如何得到解
老师以最短路径问题引出动态规划

P36 动态规划的例子

最短路径问题

在这里插入图片描述

一个实例

在这里插入图片描述

蛮力算法:

穷举所有可能的起点到终点的路径;

第一个疑惑:用什么数据结构描述问题输入

在这里插入图片描述

定义子问题

有五层节点,求最短路径

可以定义子问题,c节点到T节点的最短路径

容易知道,c1到T节点,必然是走上面的2短,c2必然走下面的3更短,依次类推可以轻松得到C层的各节点到T节点的最短路径

那么C和T层可以合并

再划分子问题,B层到T层的最短路径;依次可以得出

继续划分子问题直到求S层到T层
在这里插入图片描述

子问题界定

在这里插入图片描述

为什么能用动态规划,因为子问题的解,与原问题的解存在依赖关系

在这里插入图片描述

在这里插入图片描述

举一个反例子

在这里插入图片描述

破坏了

在这里插入图片描述
此时,此例子的动态规划其实也可以理解为时分治算法,并不是一个典型的动态规划算法;只是为了引出问题。引出下面对动态规范算法设计的思考

P37 动态规划算法设计

需要考虑以下问题

在这里插入图片描述

举个栗子

在这里插入图片描述

介绍一下矩阵相乘

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

也就是矩阵A(i,j)与矩阵B(j,k)

矩阵的行数要等于列数,相乘后的结果A(i,j)*B(j,k) = C(i,k)

需要做的乘法运算为 i * j * k;

1、问题建模,把矩阵链的数据结构表示成数组,p0-pn 一共有n个矩阵,p0是第一个矩阵的行,p1是第一个矩阵的列也是第二个矩阵的行;

p0 p1 p2 p3 p4 p5 p6 p7 p8

假如第一个矩阵与第二个矩阵相乘则,乘法次数为p0 * p1 * p2

并且变换为新的矩阵,p0 p2;

优化的目标是使得乘法次数ijk最小

蛮力算法

蛮力算法也就是穷举出所有可能的矩阵相乘顺序次数的结果

相当于在矩阵直接加括号,加了括号的优先相乘
在这里插入图片描述

蛮力算法我也不知道怎么去穷举

我能想到的是,数组《p0,p1,…,pn》

构建两个栈,依次入栈;

初始化两个栈。左栈入p0,右栈入p1

然后依次入栈,也就是一边放一个,轮着来;

然后随机出栈,出栈时,两个都出栈做相乘运算,相当于加括号;

当任意栈空时,强制入栈,不当做一种入栈的顺序;

这样就两种操作,出栈和入栈,列出所有的出栈和入栈顺序就相当于穷举;

递归的二选一,得到所有的出栈和入栈序列;实现穷举

指数级复杂度;

动态规划算法

在这里插入图片描述

子问题划分

在这里插入图片描述

P38 动态规划算法递归实现

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
可以发现通过动态规划,复杂度有所下降,但仍是不理想;
在此之前的算法设计仍然可以归结是一个分治算法,没有动态规划算法的关键

分析算法

在这里插入图片描述

假设最初的问题,规模是5

第一层,根据k的位置,将会产生4个子问题组合,相当于8个子问题。

图中相同颜色的框框代表相同的子问题,可以发现相同的子问题会重复出现,重复的计算导致复杂度很高

同一个子问题被多次计算

在这里插入图片描述

如何改进
在这里插入图片描述

P39 动态规划算法的迭代实现

要实现:每个子问题只计算一次

则需要:

​ 1、明确迭代过程,要从最小的子问题算起

​ 2、考虑计算顺序

​ 3、保留结果,存储的数据结构

​ 4、如何找到解

在这里插入图片描述

在这里插入图片描述

迭代的顺序,从最小的子问题,n=1起
在这里插入图片描述

举例子

依次计算r=2,3,4…8

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

我的分析
在这里插入图片描述

在这里插入图片描述

java代码实现

//矩阵链相乘
	//问题描述:设A1,A2,...,An为矩阵序列,Ai为Pi-1*Pi阶矩阵,i=1,2,...,n.试确定矩阵的乘法顺序,使得元素相乘的总次数最少。
	//输入:数组P【p0,p1...pn】	其中p0,p1,...,pn为n个矩阵的行数与列数
	//输出:矩阵链乘法加括号的位置
	public void MatrixChain(int[] P,int n) {
		int[][] m = new int[n+1][n+1];
		int[][] s = new int[n+1][n+1];
		//遍历所有的矩阵链长度
		for(int r = 2; r <= n; r++) {
			//i为矩阵链左边界
			for(int i = 0; i <= n - r; i++) {
				//i为矩阵链左边界
				int j = i+r;
				m[i][j] = m[i][i+1] + m[i+1][j] + P[i] * P[i+1] * P[j];	//k=i+1时
				s[i][j] = i+1;											//记录划分位置k
				for(int k = i+2; k <= j - 1; k++) {
					int temp = m[i][k] + m[k][j] + P[i] * P[j] * P[k];
					if(temp < m[i][j]) {
						m[i][j] = temp;
						s[i][j] = k;
					}
				}
			}
		}
		
		//追踪解
		getMatrixChain(P, m, s, 0, n);
	}

	private void getMatrixChain(int[] P, int[][] m, int[][] s, int i, int j) {
		System.out.println("m[" + i + "][" + j + "]最少乘法次数为:" + m[i][j]);
		int k = s[i][j];
		if(j - i < 2)  {
			return;
		}
		
		getMatrixChain(P, m, s, i, k);
		getMatrixChain(P, m, s, k, j);
	}

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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值