递推与储存,是动态规划的关键



小智最近由于项目需要,经常要接触到一些规划类的问题。那今天就给大家讲一讲旅行商问题及其解法吧。


旅行商问题,即TSP问题(Travelling Salesman Problem)。问题是,有一个旅行商人要拜访n个城市,每个城市只能拜访一次,而且最后要回到原来出发的城市。这位商人如何设计拜访顺序,使走过的路径最短? 


这种求最短距离问题有非常多实际场景会涉及到,比如,快递公司为了使城市A到城市B的快递件运输速度达到最快,他们会选择城市A到城市B的最短路径来进行运输。再比如,游戏当中的角色移动时,需要寻找到一条最短路径进行移动,这样游戏中的角色才不会失真。又比如,网络当中需要有路由算法,用于计算最短的信息跳转路径。


一款RPG游戏的角色移动演示,你会发现角色走路沿最短路径。如果不这样设计,游戏的体验感则会非常糟糕


这么多实际的精彩案例,旅行商问题确实值得研究,而且学习完说不定能派上用场。


对于这类问题,我个人这次倾向使用动态规划算法来解这道问题,得到他的精确解。


动态规划这种技术也是有非常多实际场景会涉及到,比如,以动态规划为基础原理的维特比算法,现今常用于语音识别这个领域。再比如,生物信息学中需要进行DNA之间的比对,找出最长的公共DNA部分。


语音识别技术使得人机交互的难度不断下降,其背后离不开数学


这里首先讲解一下动态规划的步骤:

1、分段:将原问题分解为若干个相互重叠的子问题。

2、分析:分析问题,找出递推式。

3、求解:利用递推式自底向上计算,实现动态规划过程。


其实,动态规划的精妙之处在于,每个子问题只求解一次,并将解保存在一个表格中,当需要再次求解此子问题时,只是简单地通过查表获得该子问题的解,避免大量的重复计算。


为了更好地在旅行商问题上讲解动态规划算法,这里讲一个简单的例子,隔壁村的老王要去这4座城市拜访,城市之间的距离如下图。


四座城市之间的距离示意图


图中一共有4座城市,城市0、城市1、城市2、城市3。小智目测走完这几个城市的最短路程为10(城市0→城市1→城市2→城市3→城市0)


人总是有直觉,而且有时会非常准。


当然,我们要用科学而完整的方法而得到最短的拜访路径,不能总是依赖直觉,尽管直觉经常是对的。我们先用穷举法列一下所有路径:



这是暴力的穷举法,一共需要运算3!×4=24次加法。


暴力法是能得到结果,但是时间复杂度是阶乘阶O(n!),是算法当中复杂度极高的等级。

常见的算法时间复杂度由小到大依次为:

常数阶Ο(1)<对数阶Ο(logn)<线性阶Ο(n)<线性对数阶Ο(nlogn)<平方Ο(n^2)<立方阶Ο(n^3)<…<指数阶Ο(2^n)<阶乘阶Ο(n!)。

 

从动态规划的角度看,假如我们找到一条最短的路径:城市0→城市1→城市2→城市3→城市0


那么,城市1→城市2→城市3→城市0必然是城市1到城市0的一条最短路径。

假设该路径不是城市1到城市0的一条最短路径,设该路径的总路程为d,那么会有一条新的路径作为城市1到城市0的最短路径d’, d > d’,那么城市0→新路径→城市0为完成拜访的最短路径,与原假设”找到一条最短路径:城市0→城市1→城市2→城市3→城市0”矛盾。


按照上述结论,可以将路径进行分解。设最短路径的符号标记为 L。那么:


L(城市0→城市0) = L(城市0→城市1) + L(城市1到城市0)


请注意,城市0是起点城市和终点城市。


假如已经获知各座城市到城市0的最短路径,那么从城市0到城市0归结起来一共有三种路径:


L(城市0→城市1) + L(城市1到城市0)

L(城市0→城市2) + L(城市2到城市0)

L(城市0→城市3) + L(城市3到城市0)


在上述路径找到最短的路径,即为拜访所有城市的最短路径。


上述路径可以继续分解。比如,以第1条路径为例:


L(城市1到城市0) = L(城市1→城市2) + L(城市2到城市0)


就这样,路径一直可以被分解,到什么时候结束呢?假设继续以上述的L(城市1到城市0)为例,继续对L(城市2到城市0)进行分解:


L(城市2到城市0) = L(城市2→城市3) + L(城市3到城市0)


由于城市1、城市2之前已经出现过了,因此L(城市3到城市0)只能等于L(城市3→城市0)


至此,城市间的路径全部可以被分解。


我们以符号来表达上述的过程。假设 d(i, V) 表示从城市 i经过城市集合 V各点一次后返回到出发点的最短距离。d(i, V) 可以按照一下方式分解:




其中,Cki 为城市 k 到城市的距离。


这样,动态规划的递推式出来了。


从城市0出发,经过城市1、2、3后回到城市0的最短路径长度为:



这个是最后一个阶段的决策,它必须依据 d(1, {2,3})d(2, {1,3}) 和 d(3, {1,2})的计算结果,继续分解:



当然,还可以继续进行分解:



上述过程可以发现,在计算的时候,可以不断引用先前的计算结果,这就是动态规划的特点。我们将上述过程在表格中把填写一下:



至此,发现拜访完所有城市的最短距离为10,印证了小智原来的想法。


上述执行加法的次数:



时间复杂度为O(2n)。动态规划相比起穷举法下降了一个等级,这个算法起到了重要的价值。


完成原理阐述,是时候写代码了,先整理一下伪代码:

1、初始化一个表格d,用于记录计算结果。并以距离初始化第0列

2、循环j=1:2n-1-1

循环 i=(1:n,且不包含在V[j])

        循环 V[j]中的所有元素

         d[i][j] = min(c[i,k], d[k][V[j]去掉k元素后对应的序号])

3、计算d[0][2n-1-1] = min(c[0,k] +d[k][2n-1-2],此为最短路径长度


这里需要注意的是,集合V是从小变大,要先算V较小的部分,因此要找一个方式来表达集合V,然后对计算进行顺序。


这里将数字转换为二进制序列,以表示集合V拥有的元素,比如:[1,0,0],可表示集合V只包含元素1,[0,1,1],可表示集合V包含元素2和元素3。


二进制数可以映射到自然数区,比如:


0 →[0,0,0]、1 → [1,0,0]、2 → [0,1,0]、3 → [1,1,0]

4 →[0,0,1]、5 → [1,0,1]、6 → [0,1,1]、7 → [1,1,1]


为了实现集合从小到大的计算顺序,对二进制序列进行特别的排序,其中第一排序条件是序列的总和,升序。第二排序条件是序列代表的数字,升序,转换为以下排序。



这样,按照上述表格中的序号作为顺序进行计算即可。


可以动手编程了。我们挑一道更难的题目,有10座城市的TSP问题:


另一道题目:10座城市之间的距离矩阵


有了想法很快就可以付诸实践了(回复“TSP程序”可以获得程序),这是最美妙的地方。按照上述流程,最短路径距离为284,最短路线:


0→3→1→5→7→6→2→8→4→9→0


当然,这个并不是一个完美的解法,随着城市数量的增加,计算难度呈指数增长,目前关于TSP在多项式时间内的解法目前还没出现,但我相信未来一定会诞生。


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

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

相关文章

SQL 标量值函数的调用

调用 MS SQL 标量值函数,应该在函数前面加上 "dbo.",否则会报 “不是可以识别的 内置函数名称”错误。例如 DECLARE WhichDB TINYINT; SELECT WhichDB dbo. user_GetWhichDB(1);--看看是哪个数据库的 另外,标量值函数就相当于…

dotnet core TargetFramework 解析顺序探索

dotnet core TargetFramework 解析顺序测试Intro现在 dotnet 的 TargetFramework 越来越多,抛开 .NET Framework 不谈,如果一个类库支持多个 TargetFramework 应用实际运行的时候会使用哪个版本的 API 呢,之前一直都是想当然的自以为是了&…

java递归单链表查找中间元素_《数据结构与算法——C语言描述》答案 3.11 查找单链表中的特定元素(递归)...

转载请注明出处:http://blog.csdn.net/xdz78#include #include //查找单链表中的特定元素,《数据结构与算法——c语言描述》 3.11 答案int count;//全局变量自动初始化为0int m;//需要查找的元素大小typedef struct student {int data;struct student *n…

python调用robotframework_robotframework+python接口自动化的点滴记录(2)

1.在循环体内,赋值语句的前后名称不能一样,否则在跑循环的第二次时就会报错:TypeError: not all arguments converted during string formatting这样写是错的:${设置计划接口_请求body} string format ${设置计划接口_请求body}…

这种感觉真爽

今天接到客户的修改需求,说了一大段话,然后我们开始讨论解决方案。最后自己来负责前台的修改。看了六七个小时的代码,最后修改了一行。达到了要求。想起了以前课文中学到的一句话:画一条线1美元,知道在哪里画这条线999…

大数据时代,掌握数据分析需要做到这几点

这些年来,随着进入大数据时代,各行各业均有一个词频频被提到,那就是数据分析。那么数据分析究竟是什么呢?数据分析就是指用适当的统计分析方法对收集来的大量数据进行处理分析,提取有用信息并形成结论,从而…

93.7%的程序员!竟然都不知道Redis为什么默认16个数据库?

背景在实际项目中redis常被应用于做缓存,分布式锁/消息队列等。但是在搭建配置好redis服务器后很多朋友应该会发现和有这样的疑问,为什么redis默认建立了16个数据库,16个数据库的由来redis是一个字典结构的存储服务器,一个redis实…

python tablewidget 颜色_QT中,QTableView鼠标移动到item上时该item所在行的背景颜色变成其他颜色,这要怎么实现...

展开全部//不解释,自己看。不保证完整,仅供思路参考#include #include "TableView.h"#include #include int main(int argc, char *argv[]){QApplication a(argc, argv);QStandardItemModel model;for ( int col 0; col {QList list;for ( in…

java8 垃圾 不同_【不同的Java垃圾回收器的比较】

现在已经是2014年了,但是对大多数开发人员而言有两件事情仍然是个谜——java垃圾回收以及异性(码农又被嘲笑了)。由于我对后者也不是特别了解,我想我还是试着说说前者吧,尤其是随着Java8的到来,这个领域也发生了许多重大的变化及提…

。。。第一次。。。

记得第一次给你发短信。。问你。。数据结构期末考试有没有范围啊。。没有告诉你。。那次只是给你发短信的借口。。记得第一次打电话给你。。问你。。那个。。什么什么。。的那道题。。你会做吗。。第一次在电话里听你的声音。。是那样的甜美。。记得第一次和安子。阿昆吃饭的时…

“一边熬夜一边求不要猝死”,90后养生朋克指南,条条扎心!

随着一批又一批的90后步入中年秃头、失眠、衰老...健康的压力如影如随是时候开始养生朋克了当代青年:养生朋克指南养生朋克一边作死一边自救的养生方式比如一边熬夜一边涂贵价护肤品用最贵的眼霜 熬最长的夜心理活动经常是:一边熬夜一边祈祷自己不要猝死…

EntityFramework Core查询数据基本本质

【导读】在EntityFramework Core中、当查询出数据后,是如何将数据映射给实体的呢?本节我们预先做个基本探讨,后续给出其底层原理本质前不久,我们在探索性能时,给出利用反射达到性能瓶颈时的方案即使用委托,…

pythonmt4通讯swot矩阵_swot分析矩阵范例(各部门)

优势(Strengths)S1.团队工作氛围和谐融洽,作风吃苦耐劳,积极主动、自我改进意识强S2.品质管控专业人才工作能力强、沟通能力强,执行力坚决S3.产品质量管控体制、流程健全,拥有质量监督管控权S4.产品检测、试验设备齐全&#xff0c…

2009从知到行知识管理培训公开课最后一期

由知识管理中心(Knowledge Management Center)举办的“从知到行:知识管理理论与实施”培训班第十六期将于2009年11月26-27日于北京举办,这也是KMC举办的2009年最后一期面向CKO、知识管理总监、经理和知识管理专员等知识管理实施人…

java socket 多次write_java NIO2异步socket的write事件与read事件的完成次数不一致是怎么回事...

引用来自“Black_JackQ”的评论异步的,client需多次read处理完数据。是这样做的,但是目前观察消息接受率只有70%左右,代码如下:socket.read(byteBuffer, null, new CompletionHandler() {Overridepublic void completed(Integer r…

万级 K8S 集群背后,etcd 如何保持稳定性?

这几年,随着 Kubernetes 成为容器编排领域霸主,etcd 越来越火,GitHub star 已超过 34.2K。这与它的应用场景广泛密不可分,从服务发现到分布式锁,从配置存储到分布式协调,可以说,etcd 已成为云原…

mysql 10分钟一聚合_SQL-根据DateTime查询多个聚合-MySQL

这是一个复杂的过程.但是我有一个表,其中包含一个DATETIME字段,以及一些其他的int和float字段,需要对其求和并求平均值.我们希望基于时间戳在此表上进行求和和平均,最终旨在开发3个在某种意义上可以相互补充的查询.所以能力看起来像这样TIMESTAMP |subj_diff| SCR2 | SCR32011-…

qdialog 只有点击才能获得焦点_4 个突破点,让你的 Banner 点击率提升10倍

双 11 刚过,双 12又来了每年这个时候作为一名设计师,真的很难...老板压着做电商 banner还有很多人指指戳戳让你改稿好不容易按照别人的想法过稿结果banner 的点击率还不高其实,只需要稍微调整视觉重点你的电商banner 就会变得变得更吸引人&am…

判断文件是否存在一个API函数

一、声明(方式有两种): 1. functionPathFileExists(pszPath:string):Bool;stdcall;externalshlwapi.dllNamePathFileExistsA;2. functionPathFileExistsA(pszPath:string):Bool;stdcall;externalshlwapi.dll;二、使用(此处用第二种方式&#…

穿背心的老院士,86岁,重病,还在敲代码,单手!

昨天有幸看到了一个视频,视频中,一位老先生穿着朴素的白背心,伏在桌上,对着电脑,一手按着写满密密麻麻数学公式的本子,另一只手仅用单指吃力又缓慢地按着键盘。老先生全神贯注地研究他是 “背心院士” 高伯…