算法设计与分析——动态规划

本文详细介绍了动态规划的概念及其在解决斐波那契数列、K级图问题和格路问题中的应用。动态规划通过数组记录子问题状态,避免重复计算,提高效率。文中通过实例展示了如何利用动态规划求解最短路径问题,强调了状态转移方程的重要性。
摘要由CSDN通过智能技术生成
动态规划本质上就是一种带有数组的分治思想
那么动态规划什么时候用呢?
类似于这种

在这里插入图片描述

	可以发现,当计算 f(n) 的时候,需要用到 f(n 2 1),当计算 f(n - 1) 的时候,还是
需要用到 f(n - 2),这样,一个子问题就要计算 k 次,显然增加了时间复杂度,这种时候
就需要用到动态规划了,将所有的子问题都用一个数组记录下来,避免重复计算,可以说,
动态规划的精髓就在于数组记录状态和状态转移方程。

DP:1、分析子问题的依赖关系(子问题:重叠)
	2、采用自底向上的方法依次求解
	3、从最小规模求解,一直到最大子问题
	注:子问题不管是否用到,都要计算出来保存起来
		子问题放到表格里面。

一、斐波那契数列

int get(int n)
{
	if(f[n])
	{
		return f[n];
	}
	f[n] = get(n - 1) + get(n - 2);
	return f[n];
}
在使用前将 f[0] 和 f[1] 初始化为 1 即可。

二、K级图问题

	K 级图定义为:每一级有若干个结点,一共有若干个级,每一级只能由上一级指入,
只能指向下一级,且从一级前往下一级的节点会有 h 的权重,并且第一级和最后一级
都只有一个节点,求从开始节点到最后节点的最短路径。

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

可以看到,要想求 7 号的最短路径,要先求出 456 的最短路径,如果采用递归的
方式,那么势必要计算 32号节点的最短路径,或许这对于这里的二号节点是可以接受
的,但是当级数增加,级内节点增加,那么一个 k 号节点的重复计算次数便不可估计,所以
递归方法便变得不可接受了,如果用数组将 k 号节点的最短路径保存起来,当用到的时候
取出来,这样便可以避免重复运算了,这就是动态规划的思维,所以这道题可以这样求解
	1、定义一个节点类型
		struct Node
		{
			int min_path;
			Node * from;
		};
		struct point
		{
			int x, y;
		};
		同时定义一个二维数组或者用 map<point, int> 来保存点与点直接的消耗
	2、每一节点的 min_path = min(上一级各点 min_path + 上一级各点到该点的消耗)
	3、在计算 min_path 的同时更新该点的 from 为使得 min_path 最小的上一级点的
		编号
	4、最后的 min_path 就是该点的 最短路径长度,最短路径只需要根据 from 字段
		依次向前寻址即可
	当然,在做这一切之前将最简单的子问题 0号的min_path 初始化即可

三、格路问题

格路问题定义:对于一个给定的网格,每一条路径上都有一个权值,求从(00)到
(m,n)的最短路径
	这个问题本质上与 K 级图类似,求解(m,n)的最短路径,由于最短路径只能从
上或者右走,所以(m,n)有两个子问题,左边或者下边,所以只需要求解 min(下边
最短路径+向上的边,左边最短路径+向右的边),同样,子问题再分解成为子问题,
这时你会发现,有很多点的子问题都要重复计算,所以,可以采用二维数组将这个最短路
径的数值保存起来,即用即取,于是
	1、定义一个结构体
		struct Node
		{
			int min_path;
			Node * from;
		};
	2、初始化
		最简单的子问题是 第0行 和 第0列,因为他们只有一个来源,因此只需要不断加
		起来计算 min_path 就好
	3、对于一般的点来说,进行两重循环,按照下面的状态转移方程计算
		min_path = min(下边最短路径+向上的边,左边最短路径+向右的边);
	4、输出(m,n)的 min_path 即可,求最短路径的方式只需要从(m,n)开始不断的
		“from” 即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值