动态规划理论:一篇文章带你彻底搞懂最优子结构、无后效性和重复子问题

动态规划理论:一篇文章带你彻底搞懂最优子结构、无后效性和重复子问题

什么样的问题可以用动态规划解决?解决动态规划问题的一般思考过程是什么样的?

一个模型三个特征理论讲解

动态规划能解决的问题有什么规律可循呢?总结为“一个模型三个特征”

一个模型:动态规划适合解决的问题的模型,该模型定义为“多阶段决策最优解模型”

一般用动态规划来解决最优问题,解决问题的过程,需要经历多个决策阶段,每个决策阶段对应一组状态,然后寻找一组决策序列,经过这组决策序列,能产生最终期望求解的最优解

三个特征:最优子结构、无后效性和重复子问题

1,最优子结构

问题的最优解包含子问题的最优解,即后面阶段的状态可以通过前面阶段的状态推导出来

2.无后效性

推导我们阶段的状态时候,只关心前面阶段的状态值,不关心这个是怎么一步步推导出来的,只有满足前面提到的动态规划问题模型,基本都会满足无后效性

3.重复子问题

不同决策序列,到达某个相同的阶段时,可能会产生重复的状态

“一个模型三个特征”实例剖析

有一个n*n的矩阵w[n][n],矩阵中存储的都是正整数,需要将棋子从左上角移动到右下角,每次只能往右或者向下移动一位,把每条路径经过的数字加起来看做路径的长度,那么从左上角移动到右下角的最短路径长度是多少?

1 3 5 9

2 1 3 4

5 2 6 7

6 8 4 3 (1是起点,3是终点)

这个问题是否符合“一个模型”?

从(0,0)移动到(n-1,n-1)总和走2*(n-1)步,每个阶段都有向右或者向下走两种决策,每个阶段都会对应一个状态集合,把状态定义为min_dist(i,j),i表示行,j表示列,min_dist(i,j)表达式的值表示从(0,0)到(i,j)的最短路径长度,所以这个问题是一个多阶段决策最优解问题,符合动态规划的模型

初始阶段0:1

阶段1:2 or 3

阶段2:5 or 1 or 5

阶段3:6 or 2 or 3 or 9

阶段4:8 or 6 or 4

阶段5:4 or 7

阶段6:3

是否符合“三个特征”?

用回溯算法解决这个问题,比如写一下代码,画一下递归树,发现递归树中有重复节点,重复节点表示从左上角到节点对应的位置有多种路线,说明这个问题有重复子问题

走到(i,j)这个位置,只需要关心(i-1,j),(i,j-1)两个位置对应的状态,并不关心棋子是通过什么样的路线到达这两个位置的,符合无后效性这个特征

min_dist(i,j)可以通过min_dist(i,j-1)和min_dist(i-1,j)两个状态推导出,符合最优子结构

两种动态规划解题思路总结

把解决动态规划问题一般有两个思路,状态转移表法和状态转移方程法

1.状态转移表法

能用动态规划解决的问题都可以使用回溯算法的暴力搜索解决,当我们拿到问题的时候先用简单的回溯算法解决然后定义状态,每个状态表示一个节点,画出递归树,看是否存在重复子问题,以此来寻找规律,看是否能用动态规划解决

找到重复子问题之后,有两种思路,一是直接用回溯加“备忘录”来避免重复子问题,二是使用动态规划解决方案,状态转移表法

状态转移表法是:先画出一个状态表,表一般是二维的,每个状态包含三个变量,行、列、数组值,根据决策的先后过程,从前往后,分阶段填充每个状态,将这个递推填表的过程,翻译成代码,就是动态规划代码

尽管大部分状态表都是二维的,如果问题的状态比较复杂,需要很多变量来表示,对应的状态表可能就是高维的,那么就不适合用状态转移表法

如何套用这个状态转移表法,来解决之前那个矩阵最短路径的问题?

从起点到终点,有很多不同走法,可以穷举所有走法,对比找出一个最短走法,如何才能无重复又不遗漏穷举所有走法?用回溯算法这个有规律的穷举算法:

private int minDist = Integer.MAX_VALUE;   //全局变量或者成员变量
//调用方式:minDistBacktracing(0,0,0,w,n):
public void minDistBT(int i ,int j,int dist,int[][] w ,int n){
	//到达了n-1,n-1这个位置
	if(i == n && j == n){
		if(dist < minDist) minDist = dist;
		return;
	}
	if(i < n ){   //往下走,更新i = i+1;j=j
		minDistBT(i + 1,dist+w[i][j],w,n);
	}
	if(j<n){    // 往右走,更新i=i, j = j +1
		minDistBT(i,j+1,dist+w[i][j],w,n);
	}
}

有了回溯代码,画出递归树,以此来寻找重复子问题,一个状态包含三个变量(i,j,dist),尽管(i,j,dist)没有重复的,但是(i,j)有很多重复的,对于(i,j)重复的节点,选择dist最小 的节点继续递归求解,其他节点舍弃

是否能用动态规划区解决?

画出二维状态表,行和列代表棋子所在位置,数值表示从起点到这个位置的最短路径

先初始化第0行、第0列

1 4 9 18

3 * * * 第一行:min(3+1,4+1) min(4+3,9+3) min(7+4,18+4)

8 * * * 第二行:min(8+2,4+2) min(6+6,7+6) min(12+7,11+7)

14 * * * 第三行:min(14+8,6+8) min(14+4,12+4) min(16+3,18+3)

所以代码为:

public int minDistDP(int[][] matrix , int n ){
	int[][] states = new int[n][n];
	int sum = 0 ;
	for(int j = 0 ; j < n ; ++j){     //初始化states的第一行数据
		sum += matrix[0][j];
		states[0][j] = sum;
	}
	sum = 0;
	for(int i = 0 ; i < n ; ++i){    //初始化states的第一列数据
		sum += matrix[i][0];
		states[i][0] = sum;
	}
	for(int i = 1;i < n ;++i){
		for(int j = 1 ; j < n ; ++j){
			states[i][j] = matrix[i][j] +Math.min(states[i][j-1],states[i-1][j]);
		}
	}
	return states[n-1][n-1];
}

2.状态转移方程法

需要分析某个问题如何通过子问题来递归求解,即最优子结构,根据最优子结构,写出递归公式,即状态转移方程,有了方程,代码实现简单了,一种是递归+备忘录,一种是迭代递推

递归方程是;
m i n d i s t ( i , j ) = w [ i ] [ j ] + m i n ( m i n d i s t ( i , j 1 ) , m i n d i s t ( i 1 , j ) ) min_dist(i,j) = w[i][j]+min(min_dist(i,j-1),min_dist(i-1,j))

第一种:递归+备忘录 将方程翻译成代码
private int[][] matrix = {{1,3,5,9},{2,1,3,4},{5,2,6,7},{6,8,4,3}};
private int n = 4;
private int[][] mem = new int[4][4];
public int minDist(int i , int j){   //调用minDist(n-1,n-1)
	if( i == 0 && j == 0) return matrix[0][0]
	if(mem[i][j] > 0) return mem[i][j];
	int minLeft = Integer.MAX_VALUE;
	if(j-1 >= 0 ){
		minLeft = minDist(i,j-1);
	}
	int minUp = Integer.MAX_VALUE;
	if(i-1 >= 0){
		minUp = minDist(i-1,j);
	}
	
	int currMinDist = matrix[i][j] + Math.min(minLeft,minUp);
	mem[i][j] = currMinDist;
	return currMinDist;
}

四种算法思想比较分析

贪心、分治、回溯和动态规划之间的区别和联系

将贪心、回溯、动态规划分为一类,将分治单独分为一类,前三个算法解决问题的模型可以抽象成多阶段决策最优解模型,分治算法解决的问题尽管大部分都是最优解问题,但是并不能抽象成多阶段决策模型

硬币找零问题

有几种不同币值的硬币v1 , v2,……,vn(单位是元),要支付w元,求最少需要多少个硬币,比如,我们有3种不同的硬币,1¥,3¥,5¥,我们要支付9元,最少需要3个硬币(3个3元的硬币)

可以看做爬阶梯问题可以分为1,3,5步,怎么最少走到9步,动态转移方程f(9) = 1+min(f(8),f(6),f(4))

即f(n) = 1 + min(f(n-1) , f(n-3) ,f(n-5))

发布了75 篇原创文章 · 获赞 9 · 访问量 9180

猜你喜欢

转载自blog.csdn.net/ywangjiyl/article/details/104717935
今日推荐