详细实例说明+典型案例实现 对动态规划法进行全面分析 | C++

news2024/11/15 11:09:01

第三章    动态规划法


目录

●第三章    动态规划法

●前言

●一、动态规划法是什么?

1.简要介绍

2.生活实例

●二、动态规划法对斐波那契数列的优化

1.优化方法

2.优化核心代码片段

3.代码实现以及结果展示 

●三、动态规划法的典型案例——最短总距离

1.具体情况

2.代码展示(C++)

3.代码结果展示

●总结


前言

   简单的来说,算法就是用计算机程序代码来实现数学思想的一种方法。学习算法就是为了了解它们在计算机中如何演算,以及在当今的信息时代,它们是如何在各个层面上影响我们的日常生活的,从而提高我们的逻辑思维能力和处理实际问题的能力。善用算法、巧用算法,是培养程序设计逻辑的重中之重,许多实际的问题都可用多个可行的算法来解决, 但是要从中找出最优的解决算法却是一项挑战。


一、动态规划法是什么?

1.简要介绍

         20世纪50年代初,动态规划法由美国数学家R.E.Bellman所创造,它很类似于分治法并且用来研究多阶段决策问题的优化过程和对问题最优解的求法。动态规划法的核心做法:如果一个问题的答案与子问题相关的话,就能将这个大问题拆解成多个子问题,并且将每个子问题的答案储存起来用于下一次求解时的直接使用。它与分治算法最大的不同点就是在于子问题能否去进行存储的问题。

2.生活实例

        ① 一个工程队需要从一个地方往另一个地方修建下水管道。他们的出发地是A,目的地是B,其中有三级中间站(中转枢纽),两地之间的连线表示即将要修建的下水管道,并且每一级的枢纽只能与自己下一级所有的枢纽相连,而不能跨级相连(具体情况如图所示)。工程队要从总的计划方案中找出最短的路径,从而以较低的成本去完成此次任务。         运用动态规划的思想对该次任务进行分析:我们的总计划方案可以规划成多种子方案,并且每种情况下的子方案还与原来总方案之间是具有相关的关系的,是它的子问题。将每种情况下子方案的路径算出并记录下来,最终进行方案的总体比较从而得出我们要找的最短路径。

所有子方案

二、动态规划法对斐波那契数列的优化

1.优化方法

        从第二章(http://t.csdn.cn/4OxrH)我们讲解的斐波那契函数执行路径图中可知,它递归调用了多次,加法也运算了多次。这样的重复计算影响到了执行的性能和效率,根据动态规划的思想已经计算过的数据就不需要再去重复计算,也不必要再往下递归。从而我们将对它进行以下的优化:

        前面介绍中我们提到过,动态规划法的核心就是将已经计算过的数据进行记录存储。为了达到这个目的,我们可以先去设置一个用来记录值的数组countval,该数组中的每一个值将会去记录已经被计算过的斐波那契数列中的各项值,并且在记录前需要将该数组设为空。每当下一次要去计算斐波那契数列中的值时,就先去从countval中去判断,如果是空值就去继续进行计算,再将计算所得结果保存到相应下标的数组中......具体过程如下:

        ①第一次计算F1,按照斐波那契数列定义,其数值为1,将此值存入暂存区countval[0]中;

        ②第一次计算F2,按照斐波那契数列定义,其数值为1,将此值存入暂存区countval[1]中;

        ③第一次计算F3,按照斐波那契数列定义,其数值为F1+F2,即countval[0]+countval[1]=2,再将F3的值存入暂存区countval[2]中;

        ④第一次计算F4,按照斐波那契数列定义,其数值为F2+F3,即countval[1]+countval[2]=3,在将F4的值存入暂存区countval[3]中;

        ⑤第一次计算F5,按照斐波那契数列定义,其数值为F3+F4,即countval[2]+countval[3]=5,

再将F5的值存入暂存区countval[4]中,结束执行。

2.优化核心代码片段

int countval[1000] = { 0 };   //暂存区
int Fib(int n)
{
	int result;
	result = countval[n-1];
	if (result == 0)
	{
		if (n == 1 || n == 2) {
			result = 1;
		}
		else {
			result = Fib(n - 2) + Fib(n - 1);
		}
		countval[n-1] = result;
	}
	return result;
}

3.代码实现以及结果展示 

        用优化后的方法去求解第五个斐波那契数的值,并且输出暂存区中的存储数据。

 #include<iostream>
using namespace std;
int countval[1000] = { 0 };   //暂存区
int Fib(int n)
{
	int result;
	result = countval[n-1];
	if (result == 0)
	{
		if (n == 1 || n == 2) {
			result = 1;
		}
		else {
			result = Fib(n - 2) + Fib(n - 1);
		}
		countval[n-1] = result;
	}
	return result;
}
void text()
{
	int i = 0;
	cout << "请输入要求的第几个斐波那契数:";
	int x; cin >> x;
	cout << "该数为:" << Fib(x) << endl;
	cout << "暂存区中的数据:" << endl;
	while (countval[i] != 0)
	{
		cout << "countval" << "[" << i << "]" << "=" << countval[i] << endl;
		i++;
	}
}
int main()
{
	text();
}

三、动态规划法的典型案例——最短总距离

1.具体情况

        要在某地区5个城市之间去修路,将这5座城市构成一幅交通图,并且要使修的路的总距离要最短。因此对总体方案进行如下分析:

<采用避圈法分析总体方案情况如下>

情况一:W(T)=2+2+3+5=12km

情况二:W(T)=2+3+4+5=14km

        从上面各种情况中我们分析可知,情况一和情况二中子图的顶点和总体方案原图完全相同。子图的分支也是总体方案原图的子集,这些子分支刚好将图中所有城市连接起来,形成一张交通图。

2.代码展示(C++)

        使用程序代码去构建以上的具体情况,并且求解出最短路径的具体长度。

#include<iostream>
using namespace std;
#define maxnum 20   //自定义图的最大的顶点数
#define maxvalue 65535
#define yes 0    //已选用顶点
#define no -1	//非邻接顶点
typedef struct {
	char vertex[maxnum];    //顶点信息
	int g_type;      //图的类型
	int vertex_num;		//顶点的数量
	int edge_num;		//边的数量
	int edge_weight[maxnum][maxnum];	//边的权
}graphmatrix;   
void creategraph(graphmatrix& gm)
{
	int weight;  //权重
	char start_vertex, end_vertex;   //起始两顶点
	int i,j,k;
	cout << "###请输入图中各顶点信息###" << endl;
	for (i = 0; i < gm.vertex_num; i++)
	{
		cout << "第" << i + 1 << "个城市:";
		cin >> gm.vertex[i];
	}
	cout << "###请输入图中构成各边的左右顶点以及该边的权值###" << endl;
	for (k = 0; k < gm.edge_num; k++)
	{
		cout << "第" << k + 1 << "条边:";
		cin >> start_vertex >> end_vertex >> weight;
		for (i = 0; start_vertex != gm.vertex[i]; i++)     //查找始点
		{
			for (j = 0; end_vertex != gm.vertex[j]; j++)   //查找终点
			{
				gm.edge_weight[i][j] = weight;                 //找到后将权值保存
			}
		}
		if (gm.g_type == 0)
		{
			gm.edge_weight[j][i] = weight;
		}
	}
}
void clear_graph(graphmatrix& gm)
{
	for (int i = 0; i < gm.vertex_num; i++)
		for (int j = 0; j < gm.vertex_num; j++)
			gm.edge_weight[i][j] = maxvalue;
}
void min_graph(graphmatrix &gm)
{
	int min, sum=0;
	int weight[maxnum];
	char vertex_[maxnum];
	int k;

	for (int i = 1;i< gm.vertex_num; i++)
	{
		weight[i] = gm.edge_weight[0][i];       //保存邻接矩阵中的一行数据
		if (weight[i] == maxvalue)
			vertex_[i] = no;
		else
			vertex_[i] = gm.vertex[0];
	}
	vertex_[0] = yes;
	weight[0] = maxvalue;
	for (int i = 1; i < gm.vertex_num; i++)
	{
		min = weight[0];
		k = i;
		for (int j = 1; j < gm.vertex_num; j++)
		{
			if (weight[j] < min && vertex_[j]>0)   //寻找具有更小权值的边
			{
				min = weight[j];
				k = j;
			}
		}
		sum += min;    //将权值进行累加
		vertex_[k] = yes; 
		weight[k] = maxvalue;
		for (int j = 0; j < gm.vertex_num; j++)
		{
			if (gm.edge_weight[k][j] < weight[j] && vertex_ != 0)
			{
				weight[j] = gm.edge_weight[k][j];
				vertex_[j] = gm.vertex[k];
			}
		}
	}
	cout << endl;
	cout << "最短路径的总长度为:" << sum << endl;
}
void text()
{
	graphmatrix gm;

	cout << "###创建图###" << endl;
	cout << "输入图的类型(0:无向图 1:有向图):";
	cin >> gm.g_type;
	cout << "输入图中城市的数量:";
	cin >> gm.vertex_num;
	cout << "输入图中城市间路径的数量:";
	cin >> gm.edge_num;

	clear_graph(gm);
	creategraph(gm);   //构建图
	min_graph(gm);   //最小生成树算法 ,动态规划的使用块
}
int main()
{
	text();
}

3.代码结果展示


总结

        在上面我们通过通俗易懂的例子对动态规划法进行了理解,也用该方法的核心对斐波那契数列进行了优化。动态规划是分治法的一个延伸,它增加了记忆机制的使用,将处理过的子问题的答案记录下来,从而避免去重复计算。

                                               <您的三连和关注是我最大的动力>

                       🚀 文章作者:Keanu Zhang        分类专栏:算法之美(C++系列文章)

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/165924.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c语言文件操作(万字解析)

c语言文件操作一.文件的打开与关闭1.文件指针-FILE*2.文件的打开与关闭二.文件的顺序读写1.字符操作函数-fgetc和fputc2.字符串操作函数-fgets和fputs3.格式化函数-fprintf和fscanf4.二进制函数-fread和fwrite5.对比一组函数三.文件的随机读写1.fseek和ftell2.调整指针-rewind四…

Python NumPy 数组索引

前言NumPy&#xff08;Numerical Python的缩写&#xff09;是一个开源的Python科学计算库。使用NumPy&#xff0c;就可以很自然地使用数组和矩阵。NumPy包含很多实用的数学函数&#xff0c;涵盖线性代数运算、傅里叶变换和随机数生成等功能。本文主要介绍Python NumPy 数组索引…

动态内容管理

这期我们来看动态内存管理的相关知识&#xff0c;话不多说&#xff0c;我们来看今天的正题 目录 1.为什么要有动态内存管理&#xff1f; 2.动态内存函数的介绍 2.1.malloc和free 2.2.calloc 2.3.realloc 3. 常见的动态内存错误 3.1 对NULL指针的解引用操作 3.2 对动态开…

Pytorch DataLoader中的num_workers (选择最合适的num_workers值)

一、概念 num_workers是Dataloader的概念&#xff0c;默认值是0。是告诉DataLoader实例要使用多少个子进程进行数据加载(和CPU有关&#xff0c;和GPU无关) 如果num_worker设为0&#xff0c;意味着每一轮迭代时&#xff0c;dataloader不再有自主加载数据到RAM这一步骤&#xff0…

滑动列表中使用粒子特效层级问题

前言 前面几个月疯狂堆功能,现在开始疯狂加动效,每次一说到动效就脑壳痛,还不如让我写功能。这不,今天又遇到问题了。滑动列表中mask粒子特效问题遮挡。 情况1 步骤1:使用粒子特效的层级应该>当前ui层级。 例如:当前界面所在层级为2000,其上的粒子特效至少为2001。…

dp(八)买卖股票的最好时机 (一,二、三)

目录 买卖股票的最好时机(一)_牛客题霸_牛客网 买卖股票的最好时机(二)_牛客题霸_牛客网 买卖股票的最好时机(三)_牛客题霸_牛客网 假设你有一个数组prices&#xff0c;长度为n&#xff0c;其中prices[i]是股票在第i天的价格&#xff0c;请根据这个价格数组&#xff0c;返回买…

基于云的文档管理系统:DocuWare Cloud

云文档管理软件&#xff1a;DocuWare Cloud 一流的云文档管理软件和工作流自动化内容服务&#xff0c;适用于任何规模的团队和公司——在多租户云平台上交付。 DocuWare Cloud 可在订阅的基础上为不同规模的公司提供灵活的许可证。 每个订阅都涵盖全方位的服务&#xff0c;包…

dvwa中的爆破

环境&#xff1a;dvwa: 192.168.11.135 dvwa版本&#xff1a; Version 1.9 (Release date: 2015-09-19)kail机器&#xff1a;192.168.11.1561、Low级别代码&#xff1a;1、启动 burpsuite 开始抓包&#xff0c;然后点击 login&#xff0c;然后在 bp 里面就能看见抓包到的包。这…

Java集合常见面试题(二)

Collection 子接口之 List ArrayList 和 Vector 的区别? ArrayList 是 List 的主要实现类&#xff0c;底层使用 Object[]存储&#xff0c;适用于频繁的查找工作&#xff0c;线程不安全 &#xff1b;Vector 是 List 的古老实现类&#xff0c;底层使用Object[] 存储&#xff0…

谷粒学院复习

一、Mybatis Plus复习分布式系统唯一ID主键策略(面试)面试的时候就说知道有以下四种策略&#xff0c;分别介绍一下每一种&#xff0c;然后说一下项目中用的是雪花算法分类自动增长 AUTO INCREMENT就是自动增长&#xff0c;每次都会自动加一。缺点&#xff1a;如果在分库分表的场…

VUE: Vue3+TS的项目搭建及基础使用

简介 通过 Vue-cli4 创建的 Vue3TS 的项目&#xff0c;并进行一些基础使用的举例。 项目搭建 1. 进入命令提示符窗口 在要搭建项目的文件夹中&#xff0c;点击路径&#xff0c;输入CMD并按回车 2. 查看node版本、Vue-cli版本 2.1 node版本&#xff08;14.x以上&#xf…

基于域控的SSO单点登录

大家好&#xff0c;好久不见&#xff0c;今天老吕给大家来一篇偏冷门知识的文章。一、需求大型集团企业内部会有许多业务系统&#xff0c;工作人员也往往需要登录多个业务系统才能完成工作&#xff0c;这就可能会存在一些问题1、多套账号与密码需要记录或者记忆2、多次登录&…

14.live555mediaserver-setup请求与响应

live555工程代码路径 live555工程在我的gitee下&#xff08;doc下有思维导图、drawio图&#xff09;&#xff1a;https://gitee.com/lure_ai/live555/tree/master 学习demo live555mediaserver.cpp 学习线索和姿势 1.学习的线索和姿势 网络编程 流媒体的地基是网络编程&…

Git 的常用命令

Git 的常用命令 目录Git 的常用命令帮助初始化配置提交远程仓库管理版本控制删除分支管理查看文件提交、状态帮助 查看常用命令 git help查看某个命令的使用帮助 git help [命令]查看 git 使用指南&#xff08;这个命令会详细展示 git 的使用周期&#xff09; git help tut…

【BP靶场portswigger-客户端13】跨来源资源共享(CORS)-4个实验(全)

前言&#xff1a; 介绍&#xff1a; 博主&#xff1a;网络安全领域狂热爱好者&#xff08;承诺在CSDN永久无偿分享文章&#xff09;。 殊荣&#xff1a;CSDN网络安全领域优质创作者&#xff0c;2022年双十一业务安全保卫战-某厂第一名&#xff0c;某厂特邀数字业务安全研究员&…

2022.12 青少年机器人技术等级考试理论综合试卷(三级)

2022年12月 青少年机器人技术等级考试理论综合试卷&#xff08;三级&#xff09; 分数&#xff1a; 100 题数&#xff1a; 30 一、 单选题(共 20 题&#xff0c; 共 80 分) 1.舵机接到 Arduino UNO/Nano 主控板的 2 号引脚&#xff0c; 下列选项中&#xff0c; 实现舵机在 0 度…

4、字符串处理

目录 一、字符串的构造 二、字符串比较 三、字符串查找 四、字符串替换 五、字符串——数值转换 Matlab中的字符串函数有&#xff1a; 一、字符串的构造 字符串或字符串数组的构造可以通过直接给变量赋值来实现&#xff0c;具体表达式中字符串的内容需要写在单引号内。如…

ESP8266 ArduinoIDE 搭建web服务器与客户端开发

一、wifi 相关配置 1.1 无线终端 wifi 模式 此模式中&#xff0c;esp8266 会连接到指定 wifi 进行工作。 #include <ESP8266WiFi.h> // 本程序使用ESP8266WiFi库const char* ssid "home"; // 连接WiFi名&#xff08;此处使用home为示例&…

Vue2-Vue开发环境搭建

一、IDE编辑器&#xff1a;Vscode&#xff0c;自行下载安装即可 二、三种引入方式&#xff0c; 教程使用方式一引入 Vue官网&#xff1a;https://v2.cn.vuejs.org/v2/guide/installation.html 方式一&#xff1a;直接script引入 教程下载开发版本&#xff0c;下载到本地&…

使用人工智能机器人提高农业效率| 数据标注

人工智能技术创新不仅仅蔓延到智慧城市、智能建筑或新的混合工作模式&#xff1b;机器人还通过人工智能、自动拖拉机、实时监测农作物的传感器、无人机或水果和蔬菜收获机器人来彻底改变农业。今天&#xff0c;我们将向您介绍一些已经在农业中使用的最有趣的AI技术&#xff0c;…