动态规划法,回溯法,分支限界法求解TSP问题实验报告

合集下载

TSP问题求解实验报告

TSP问题求解实验报告

TSP问题求解(一)实验目的熟悉和掌握遗传算法的原理,流程和编码策略,并利用遗传求解函数优化问题,理解求解TSP问题的流程并测试主要参数对结果的影响。

(二)实验原理巡回旅行商问题给定一组n个城市和俩俩之间的直达距离,寻找一条闭合的旅程,使得每个城市刚好经过一次且总的旅行距离最短。

TSP问题也称为货郎担问题,是一个古老的问题。

最早可以追溯到1759年Euler提出的骑士旅行的问题。

1948年,由美国兰德公司推动,TSP成为近代组合优化领域的典型难题。

TSP是一个具有广泛的应用背景和重要理论价值的组合优化问题。

近年来,有很多解决该问题的较为有效的算法不断被推出,例如Hopfield神经网络方法,模拟退火方法以及遗传算法方法等。

TSP搜索空间随着城市数n的增加而增大,所有的旅程路线组合数为(n-1)!/2。

在如此庞大的搜索空间中寻求最优解,对于常规方法和现有的计算工具而言,存在着诸多计算困难。

借助遗传算法的搜索能力解决TSP问题,是很自然的想法。

基本遗传算法可定义为一个8元组:(SGA)=(C,E,P0,M,Φ,Г,Ψ,Τ)C ——个体的编码方法,SGA使用固定长度二进制符号串编码方法;E ——个体的适应度评价函数;P0——初始群体;M ——群体大小,一般取20—100;Ф——选择算子,SGA使用比例算子;Г——交叉算子,SGA使用单点交叉算子;Ψ——变异算子,SGA使用基本位变异算子;Т——算法终止条件,一般终止进化代数为100—500;问题的表示对于一个实际的待优化问题,首先需要将其表示为适合于遗传算法操作的形式。

用遗传算法解决TSP,一个旅程很自然的表示为n个城市的排列,但基于二进制编码的交叉和变异操作不能适用。

路径表示是表示旅程对应的基因编码的最自然,最简单的表示方法。

它在编码,解码,存储过程中相对容易理解和实现。

例如:旅程(5-1-7-8-9-4-6-2-3)可以直接表示为(5 1 7 8 9 4 6 2 3)(三)实验内容N>=8。

TSP问题的解决方案

TSP问题的解决方案

《算法设计与分析》实验报告一学号:姓名:日期:20161230 得分:一、实验内容:TSP问题二、所用算法的基本思想及复杂度分析:1、蛮力法1)基本思想借助矩阵把问题转换为矩阵中点的求解。

首先构造距离矩阵,任意节点到自身节点的距离为无穷大。

在第一行找到最小项a[1][j],从而跳转到第j行,再找到最小值a[j][k],再到第k行进行查找。

然后构造各行允许数组row[n]={1,1…1},各列允许数组colable[n]={0,1,1….1},其中1表示允许访问,即该节点未被访问;0表示不允许访问,即该节点已经被访问。

如果改行或该列不允许访问,跳过该点访问下一节点。

程序再发问最后一个节点前,所访问的行中至少有1个允许访问的节点,依次访问这些节点找到最小的即可;在访问最后一个节点后,再次访问,会返回k=0,即实现访问源节点,得出一条简单回路。

2)复杂度分析基本语句是访问下一个行列中最小的点,主要操作是求平方,假设有n个点,则计算的次页脚内容1数为n^2-n。

T(n)=n*(n-1)=O(n^2)。

2、动态规划法1)基本思想假设从顶点s出发,令d(i, V’)表示从顶点i出发经过V’(是一个点的集合)中各个顶点一次且仅一次,最后回到出发点s的最短路径长度。

推导:(分情况来讨论)①当V’为空集,那么d(i, V’),表示从i不经过任何点就回到s了,如上图的城市3->城市0(0为起点城市)。

此时d(i, V’)=Cis(就是城市i 到城市s 的距离)、②如果V’不为空,那么就是对子问题的最优求解。

你必须在V’这个城市集合中,尝试每一个,并求出最优解。

d(i, V’)=min{Cik +d(k, V’-{k})}注:Cik表示你选择的城市和城市i的距离,d(k, V’-{k})是一个子问题。

综上所述,TSP问题的动态规划方程就出来了:2)复杂度分析和蛮力法相比,动态规划求解tsp问题,把原来时间复杂性O(n!)的排列转化为组合问题,从而降低了时间复杂度,但仍需要指数时间。

分支限界法——TSP问题讲诉

分支限界法——TSP问题讲诉

算法中while循环的终止条件是排列树的一个叶结点成为 当前扩展结点。当s=n-1时,已找到的回路前缀是x[0:n1],它已包含图G的所有n个顶点。因此,当s=n-1时,相 应的扩展结点表示一个叶结点。此时该叶结点所相应的回 路的费用等于cc和lcost的值。剩余的活结点的lcost值不 小于已找到的回路的费用。它们都不可能导致费用更小的 回路。因此已找到叶结点所相应的回路是一个最小费用旅 行售货员回路,算法可结束。 算法结束时返回找到的最小费用,相应的最优解由数组v 给出。
0
当前最优解,故没必要扩展
结点C
结点I本身的费用已高于当前 最优解,故没必要扩展结点I
此时,优先队列为空,算法 终止。
算法的while循环体完成对排列树内部结点的扩展。
对于当前扩展结点,算法分2种情况进行处理:
①首先考虑s=n-2的情形,此时当前扩展结点是排列树中某个叶结点的父结 点。如果该叶结点相应一条可行回路且费用小于当前最小费用,则将该叶结 点插入到优先队列中,否则舍去该叶结点。 ②当s<n-2时,算法依次产生当前扩展结点的所有儿子结点。由于当前扩展 结点所相应的路径是x[0:s],其可行儿子结点是从剩余顶点x[s+1:n-1]中选 取的顶点x[i],且(x[s],x[i])是所给有向图G中的一条边。对于当前扩展结点 的每一个可行儿子结点,计算出其前缀(x[0:s],x[i])的费用cc和相应的下界 lcost。当lcost<bestc时,将这个可行儿子结点插入到活结点优先队列中。
算法: 1.找出中间的蚂蚁离两端的距离中较小的。
a[2]=11
a[2]''=27-11=14, 因为a[2]<a[2]'',所以最小距离是11,时间11/1=11 2.找出两端的蚂蚁距两端的距离中较大的。

Tsp问题的几种算法的讲解

Tsp问题的几种算法的讲解

摘要本文分析比较了tsp问题的动态规划算法,分支界限法,近似等算法。

分析了旅行商问题的时间度特点,针对启发式算法求解旅行商问题中存在的一些问题提出了改进算法。

此算法将群体分为若干小子集,并用启发式交叉算子,以较好利用父代个体的有效信息,达到快速收敛的效果,实验表明此算法能提高寻优速度,解得质量也有所提高。

关键词:旅行商问题TSPAbstractthis paper analyzed the time complexity of traveling salesman problem,then put forward some imprivement towards the genetic algorithm for solving this problen: divding the population into some small parent individual well.so it can quickly get into convergence, the experimental result indicates the impwoved algorithm can accelerate the apeed of finding solution and improve the precision.Keywords traveling salesman problem; genetic algorithm; subset; henristic crossover operator目录1、摘要--------------------------------------------------------------12、Abstract---------------------------------------------------------13、Tsp问题的提法------------------------------------------------24、回溯法求Tsp问题--------------------------------------------35、分支限界法求Tsp问题--------------------------------------76、近似算法求解Tsp问题-------------------------------------107、动态规划算法解Tsp问题----------------------------------12引言tsp问题刚提出时,不少人都认为很简单。

动态规划法,回溯法,分支限界法求解TSP问题实验报告材料

动态规划法,回溯法,分支限界法求解TSP问题实验报告材料

TSP问题算法实验报告指导教师:季晓慧姓名:辛瑞乾学号: 1004131114 提交日期: 2015年11月目录总述 (2)动态规划法 (3)算法问题分析 (3)算法设计 (3)实现代码 (3)输入输出截图 (6)OJ提交截图 (6)算法优化分析 (6)回溯法 (6)算法问题分析 (6)算法设计 (7)实现代码 (7)输入输出截图 (9)OJ提交截图 (10)算法优化分析 (10)分支限界法 (10)算法问题分析 (10)算法设计 (10)实现代码 (11)输入输出截图 (15)OJ提交截图 (16)算法优化分析 (16)总结 (16)总述TSP问题又称为旅行商问题,是指一个旅行商要历经所有城市一次最后又回到原来的城市,求最短路程或最小花费,解决TSP可以用好多算法,比如蛮力法,动态规划法…具体的时间复杂的也各有差异,本次实验报告包含动态规划法,回溯法以及分支限界法。

动态规划法算法问题分析假设n个顶点分别用0~n-1的数字编号,顶点之间的代价存放在数组mp[n][n]中,下面考虑从顶点0出发求解TSP问题的填表形式。

首先,按个数为1、2、…、n-1的顺序生成1~n-1个元素的子集存放在数组x[2^n-1]中,例如当n=4时,x[1]={1},x[2]={2},x[3]={3},x[4]={1,2},x[5]={1,3},x[6]={2,3},x[7]={1,2,3}。

设数组dp[n][2^n-1]存放迭代结果,其中dp[i][j]表示从顶点i经过子集x[j]中的顶点一次且一次,最后回到出发点0的最短路径长度,动态规划法求解TSP问题的算法如下。

算法设计输入:图的代价矩阵mp[n][n]输出:从顶点0出发经过所有顶点一次且仅一次再回到顶点0的最短路径长度1.初始化第0列(动态规划的边界问题)for(i=1;i<n;i++)dp[i][0]=mp[i][0]2.依次处理每个子集数组x[2^n-1]for(i=1;i<n;i++)if(子集x[j]中不包含i)对x[j]中的每个元素k,计算d[i][j]=min{mp[i][k]+dp[k][j-1]};3.输出最短路径长度。

TSP问题算法分析报告

TSP问题算法分析报告

算法第二次大作业TSP问题算法分析021251班王昱(02125029)一.问题描述“TSP问题”常被称为“旅行商问题”,是指一名推销员要拜访多个地点时,如何找到在拜访每个地点一次后再回到起点的最短路径。

TSP问题在本实验中的具体化:从A城市出发,到达每个城市并且一个城市只允许访问一次,最后又回到原来的城市,寻找一条最短距离的路径。

二.算法描述2.1分支界限法2.1.1 算法思想分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。

在分支限界法中,每一个活结点只有一次机会成为扩展结点。

活结点一旦成为扩展结点,就一次性产生其所有儿子结点。

在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。

此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。

这个过程一直持续到找到所需的解或活结点表为空时为止。

2.1.2 算法设计说明设求解最大化问题,解向量为X=(x1,…,xn),xi的取值范围为Si,|Si|=ri。

在使用分支限界搜索问题的解空间树时,先根据限界函数估算目标函数的界[down, up],然后从根结点出发,扩展根结点的r1个孩子结点,从而构成分量x1的r1种可能的取值方式。

对这r1个孩子结点分别估算可能的目标函数bound(x1),其含义:以该结点为根的子树所有可能的取值不大于bound(x1),即:bound(x1)≥bound(x1,x2)≥…≥ bound(x1,…,xn)若某孩子结点的目标函数值超出目标函数的下界,则将该孩子结点丢弃;否则,将该孩子结点保存在待处理结点表PT中。

再取PT表中目标函数极大值结点作为扩展的根结点,重复上述。

直到一个叶子结点时的可行解X=(x1,…,xn),及目标函数值bound(x1,…,xn)。

2.2 A*算法算法思想对于某一已到达的现行状态, 如已到达图中的n节点, 它是否可能成为最佳路径上的一点的估价, 应由估价函数f(n)值来决定。

TSP问题——实验报告

TSP问题——实验报告

TSP问题目录1实验目的 (1)2问题描述与分析 (1)3算法分析 (1)3.1回溯法 (1)3.2 动态规划 (1)3.3 模拟退火算法 (2)4程序设计 (2)4.1回溯法 (2)4.2动态规划算法 (3)4.3模拟退火算法 (4)5实验结果及分析 (5)6实验总结 (6)7源代码 (6)1实验目的1.使用搜索方法进行TSP问题的求解2.了解相关智能算法3.了解NP难问题的求解策略2问题描述与分析某售货员要到若干城市去推销商品,已知各城市之间的路程(或旅费)。

他要选定一条从驻地出发,经过每个城市一遍,最后回到驻地的路线,使总的路程(或旅费)最小。

分析:问题的本质是搜索问题,而且这个问题是NP完全问题,问题的复杂度指数增长,所以普通的搜索无法在有限的时间里完成搜索,尽管有各种优化的算法:启发式算法、深度优先搜索、动态规划、回溯等。

都无法改变复杂度。

实际上大多时候人们并不关心NP完全问题的最优解,只要得出一个近似的解就可以了,因此,人们发明了很多算法,例如粒子群算法、遗传算法、模拟退火算法,这一类算法被称为“智能算法”,但是,他们都无法求出最优解,仅能得到近似解,但这已经足够了。

在本次试验中,一共设计了三个算法:回溯法,动态规划,模拟退火算法。

3算法分析3.1回溯法回溯法采用深度优先方式系统地搜索问题的所有解,基本思路是:确定解空间的组织结构之后,从根结点出发,即第一个活结点和第一个扩展结点向纵深方向转移至一个新结点,这个结点成为新的活结点,并成为当前扩展结点。

如果在当前扩展结点处不能再向纵深方向转移,则当前扩展结点成为死结点。

此时,回溯到最近的活结点处,并使其成为当前扩展结点,回溯到以这种工作方式递归地在解空间中搜索,直到找到所求解空间中已经无活结点为止。

旅行商问题的解空间是一棵排列树.对于排列树的回溯搜索与生成1,2,……, n的所有排列的递归算法Perm类似,设开始时x=[ 1,2,… n ],则相应的排列树由x[ 1:n ]的所有排列构成.旅行商问题的回溯算法。

TSP问题分析动态规划-分支界限法-蛮力法教学文案

TSP问题分析动态规划-分支界限法-蛮力法教学文案

T S P问题分析动态规划-分支界限法-蛮力法算法综合实验报告学号: 1004111115 姓名:李宏强一、实验内容:分别用动态规划、贪心及分支限界法实现对TSP问题(无向图)的求解,并至少用两个测试用例对所完成的代码进行正确性及效率关系上的验证。

二、程序设计的基本思想、原理和算法描述:(包括程序的数据结构、函数组成、输入/输出设计、符号名说明等)1、动态规划法(1)数据结构:①利用二进制来表示集合,则集合S可由一个十进制数x相对应,此x所对应的二进制数为y,如果y的第k位为1,则表示k存在集合S中。

例如:集合S={0,1}(其子集合为{}{0}{1}{01}),我们用二进制数11(所对应十进制数为3)表示S,11中右手边第1个数为1表示0在集合S中,右手边第二个数为1表示1在集合S中,其他位为0表示其它数字不在集合S中;同理,集合S={0,2}(其子集合为{}{0}{2}{02}可用二进制数101(所对应十进制数为5)表示(右手边第1个数为1表示0在集合S中,右手边第二个数为0表示1不在集合S中,右手边第3个数为1表示2在集合S中,则说明0,2在集合中,1不在集合中。

②利用邻接矩阵表示任意两点之间的距离例如:mp[i][j]表示点i,j两点之间的距离。

(2)函数组成①输入函数in()②利用动态规划法算法实现的求解函数solve()③主函数main()(3)输入/输出设计本程序可以通过键盘进行输入、屏幕进行输出。

(根据实际程序情况,还可以选择随机产生输入数据、将输出数据输出到文件等其它方式)这里采用随机产生输入数据,将数据输出在屏幕上的方式。

(4)符号名说明① n 表示顶点个数。

② mp[i][j] 表示顶点i和顶点j之间的距离。

③ dp[i][j] 表示顶点i经过集合S(用二进制表示的数为j)后回到起始点的最短路径和。

(5)算法描述①某一个点i不经过任意点回到起始点的最短路径和为mp[i][0](默认初始点为0)dp[i][0] = mp[i][0]; (1<=i<n)②点i经过集合S(二进制表示的数为j)的最短路径和为从点i经过集合S中的某一点k后再从该点出发,经过集合S-{k}的最小值。

回溯法实验报告

回溯法实验报告

回溯法实验报告一、实验目的本实验旨在通过应用回溯法解决一系列问题,并验证回溯法在问题求解中的有效性和实用性。

通过实际的案例分析和实验结果,掌握回溯法的应用方法和技巧。

二、实验原理回溯法是一种求解问题的通用方法,适用于那些可以分解为一组相互排斥的子问题的求解过程。

回溯法通过尝试可能的解决方案,并根据约束条件逐步构建问题的解。

实际使用回溯法求解问题时,按照如下步骤进行:1. 定义解空间:将问题的解表示为一个n维向量或n维数组,定义问题的解空间。

2. 约束条件:确定问题的约束条件,即问题的解必须满足的条件。

3. 逐步构造解:按照问题的解空间和约束条件,逐步构造问题的解。

4. 解空间的搜索:通过递归或迭代的方式,搜索解空间中的所有可能解。

5. 解的选取与判定:根据需要选择符合要求的解,并进行最优解的判定。

三、实验步骤在本次实验中,我们选择了数独问题和八皇后问题作为实验案例进行分析和求解。

1. 数独问题:数独问题是一个9×9的格子,其中每个格子中都填有一个1到9的数字。

数独谜题的目标是在每个格子中填写数字,使得每一行、每一列和每一个宫(3×3的格子)中的数字均不重复。

通过回溯法求解数独问题的步骤如下:(1)定义解空间:将数独问题的解定义为一个9×9的二维数组。

(2)约束条件:每一行、每一列和每一个宫中的数字不能重复。

(3)逐步构造解:从数独问题的左上角开始,按照行优先的顺序逐个格子地填写数字,并保证数字的唯一性。

(4)解空间的搜索:当需要填写一个新的格子时,先确定该格子可能的数字范围,然后选择一个数字填入,再递归地进行下一步搜索。

(5)解的选取与判定:当所有的格子都被填满时,即找到了一个满足条件的解。

在求解过程中,需要判断填入的数字是否符合约束条件,并进行回退操作,直到找到所有可能的解。

2. 八皇后问题:八皇后问题是一个经典的回溯法问题,要求在一个8×8的棋盘上放置8个皇后,使得它们互相之间不能攻击到对方。

分枝限界法实验报告(3篇)

分枝限界法实验报告(3篇)

第1篇一、实验目的1. 理解并掌握分枝限界法的基本原理和实现方法。

2. 通过实际编程,运用分枝限界法解决实际问题。

3. 比较分析分枝限界法与其他搜索算法(如回溯法)的优缺点。

4. 增强算法设计能力和编程实践能力。

二、实验内容本次实验主要涉及以下内容:1. 分支限界法的基本概念和原理。

2. 分支限界法在单源最短路径问题中的应用。

3. 分支限界法的实现步骤和代码编写。

4. 分支限界法与其他搜索算法的对比分析。

三、实验环境1. 操作系统:Windows 102. 编程语言:Python3.83. 开发环境:PyCharm四、实验步骤1. 算法描述:分支限界法是一种用于解决组合优化问题的算法,其基本思想是在问题的解空间树中,按照一定的搜索策略,优先选择有潜力的节点进行扩展,从而减少搜索空间,提高搜索效率。

2. 程序代码:下面是使用Python实现的分支限界法解决单源最短路径问题的代码示例:```pythonimport heapqclass Node:def __init__(self, vertex, distance, parent): self.vertex = vertexself.distance = distanceself.parent = parentdef __lt__(self, other):return self.distance < other.distancedef branch_and_bound(graph, source):初始化优先队列和已访问节点集合open_set = []closed_set = set()添加源节点到优先队列heapq.heappush(open_set, Node(source, 0, None))主循环,直到找到最短路径while open_set:弹出优先队列中最小距离的节点current_node = heapq.heappop(open_set)检查是否已访问过该节点if current_node.vertex in closed_set:continue标记节点为已访问closed_set.add(current_node.vertex)如果当前节点为目标节点,则找到最短路径if current_node.vertex == target:path = []while current_node:path.append(current_node.vertex)current_node = current_node.parentreturn path[::-1]遍历当前节点的邻居节点for neighbor, weight in graph[current_node.vertex].items():if neighbor not in closed_set:计算新节点的距离distance = current_node.distance + weight添加新节点到优先队列heapq.heappush(open_set, Node(neighbor, distance, current_node))没有找到最短路径return None图的表示graph = {0: {1: 2, 2: 3},1: {2: 1, 3: 2},2: {3: 2},3: {1: 3}}源节点和目标节点source = 0target = 3执行分支限界法path = branch_and_bound(graph, source)print("最短路径为:", path)```3. 调试与测试:在编写代码过程中,注意检查数据结构的使用和算法逻辑的正确性。

tsp实验报告

tsp实验报告

tsp实验报告TSP实验报告一、引言旅行推销员问题(Traveling Salesman Problem,TSP)是一类经典的组合优化问题,它在现实生活中有着广泛的应用。

TSP的目标是寻找一条最短路径,使得旅行推销员能够经过所有城市并回到出发点。

本实验旨在通过使用不同的算法和策略,探索解决TSP问题的方法,并比较它们的效果。

二、实验方法1. 数据集选择本实验选取了某个地区的城市坐标作为数据集,其中包含了20个城市的经纬度信息。

这些城市的位置分布较为均匀,有助于测试算法在不同城市分布情况下的表现。

2. 算法实现本实验采用了两种常见的算法来解决TSP问题:贪心算法和遗传算法。

贪心算法:该算法的基本思想是每次选择距离当前位置最近的未访问城市作为下一个目的地,直到所有城市都被访问过。

贪心算法简单直观,但不能保证获得最优解。

遗传算法:该算法通过模拟生物进化过程来解决问题。

它通过随机生成初始种群,然后通过选择、交叉和变异等操作,逐步优化种群中的个体,直到找到最优解。

遗传算法适用于求解复杂问题,但计算量较大。

3. 实验步骤首先,使用贪心算法计算出一条初始路径。

然后,利用遗传算法对该路径进行优化,得到更短的路径。

实验中,设置了合适的参数,如种群大小、交叉概率和变异概率,以获得较好的结果。

三、实验结果与分析经过多次实验,得到了贪心算法和遗传算法的结果,并与最优解进行了比较。

1. 贪心算法结果使用贪心算法,得到了一条初始路径,总长度为X。

该路径并不是最优解,但它提供了一个起点,可以作为遗传算法的输入。

2. 遗传算法结果经过遗传算法的优化,得到了一条更短的路径,总长度为Y。

与贪心算法相比,遗传算法能够通过不断迭代优化路径,找到更接近最优解的结果。

3. 与最优解的比较通过与最优解进行比较,可以评估算法的性能。

实验结果显示,贪心算法得到的路径长度为Z,遗传算法得到的路径长度为W,分别与最优解相差了A%和B%。

可以看出,遗传算法在寻找最优解方面表现更好,但仍存在一定的误差。

旅行商问题的几种求解算法比较

旅行商问题的几种求解算法比较

旅行商问题的几种求解算法比较作者:(xxx学校)摘要:TSP问题是组合优化领域的经典问题之一,吸引了许多不同领域的研究工作者,包括数学,运筹学,物理,生物和人工智能等领域,他是目前优化领域里的热点.本文从动态规划法,分支界限法,回溯法分别来实现这个题目,并比较哪种更优越,来探索这个经典的NP(Nondeterministic Polynomial)难题.关键词:旅行商问题求解算法比较一.引言旅行商问题(Travelling Salesman Problem),是计算机算法中的一个经典的难解问题,已归为NP 一完备问题类.围绕着这个问题有各种不同的求解方法,已有的算法如动态规划法,分支限界法,回溯法等,这些精确式方法都是指数级(2n)[2,3]的,根本无法解决目前的实际问题,贪心法是近似方法,而启发式算法不能保证得到的解是最优解,甚至是较好的解释.所以我认为很多问题有快速的算法(多项式算法),但是,也有很多问题是无法用算法解决的.事实上,已经证明很多问题不可能在多项式时间内解决出来.但是,有很多很重要的问题他们的解虽然很难求解出来,但是他们的值却是很容易求可以算出来的.这种事实导致了NP完全问题.NP表示非确定的多项式,意思是这个问题的解可以用非确定性的算法"猜"出来.如果我们有一个可以猜想的机器,我们就可以在合理的时间内找到一个比较好的解.NP-完全问题学习的简单与否,取决于问题的难易程度.因为有很多问题,它们的输出极其复杂,比如说人们早就提出的一类被称作NP-难题的问题.这类问题不像NP-完全问题那样时间有限的.因为NP-问题由上述那些特征,所以很容易想到一些简单的算法――把全部的可行解算一遍.但是这种算法太慢了(通常时间复杂度为O(2^n))在很多情况下是不可行的.现在,没有知道有没有那种精确的算法存在.证明存在或者不存在那种精确的算法这个沉重的担子就留给了新的研究者了,或许你就是成功者.本篇论文就是想用几种方法来就一个销售商从几个城市中的某一城市出发,不重复地走完其余N—1个城市,并回到原出发点,在所有可能的路径中求出路径长度最短的一条,比较是否是最优化,哪种结果好.二.求解策略及优化算法动态规划法解TSP问题我们将具有明显的阶段划分和状态转移方程的规划称为动态规划,这种动态规划是在研究多阶段决策问题时推导出来的,具有严格的数学形式,适合用于理论上的分析.在实际应用中,许多问题的阶段划分并不明显,这时如果刻意地划分阶段法反而麻烦.一般来说,只要该问题可以划分成规模更小的子问题,并且原问题的最优解中包含了子问题的最优解(即满足最优子化原理),则可以考虑用动态规划解决.所以动态规划的实质是分治思想和解决冗余,因此,动态规划是一种将问题实例分解为更小的,相似的子问题,并存储子问题的解而避免计算重复的子问题,以解决最优化问题的算法策略.旅行商问题(TSP问题)其实就是一个最优化问题,这类问题会有多种可能的解,每个解都有一个值,而动态规划找出其中最优(最大或最小)值的解.若存在若干个取最优值的解的话,它只取其中的一个.在求解过程中,该方法也是通过求解局部子问题的解达到全局最优解,但与分治法和贪心法不同的是,动态规划允许这些子问题不独立,(亦即各子问题可包含公共的子子问题)也允许其通过自身子问题的解作出选择,该方法对每一个子问题只解一次,并将结果保存起来,避免每次碰到时都要重复计算.关于旅行商的问题,状态变量是gk(i,S),表示从0出发经过k个城市到达i的最短距离,S为包含k个城市的可能集合,动态规划的递推关系为:gk(i,S)=min[gk-1(j,S\{j})+dji] j属于S,dji表示j-i的距离.或者我们可以用:f(S,v)表示从v出发,经过S中每个城市一次且一次,最短的路径.f(S,v)=min { f(S-{u},u)+dist(v,u) }u in Sf(V,1)即为所求2.分支限界法解TSP问题旅行商问题的解空间是一个排列树,与在子集树中进行最大收益和最小耗费分枝定界搜索类似,使用一个优先队列,队列中的每个元素中都包含到达根的路径.假设我们要寻找的是最小耗费的旅行路径,那可以使用最小耗费分枝定界法.在实现过程中,使用一个最小优先队列来记录活节点,队列中每个节点的类型为M i n H e ap N o d e.每个节点包括如下区域: x(从1到n的整数排列,其中x [ 0 ] = 1 ),s(一个整数,使得从排列树的根节点到当前节点的路径定义了旅行路径的前缀x[0:s], 而剩余待访问的节点是x [ s + 1 : n - 1 ]),c c(旅行路径前缀,即解空间树中从根节点到当前节点的耗费),l c o s t(该节点子树中任意叶节点中的最小耗费), rc o s t(从顶点x [ s : n - 1 ]出发的所有边的最小耗费之和).当类型为M i n He a p N o d e ( T )的数据被转换成为类型T时,其结果即为l c o s t的值.分枝定界算法的代码见程序.程序首先生成一个容量为1 0 0 0的最小堆,用来表示活节点的最小优先队列.活节点按其l c o s t值从最小堆中取出.接下来,计算有向图中从每个顶点出发的边中耗费最小的边所具有的耗费M i n O u t.如果某些顶点没有出边,则有向图中没有旅行路径,搜索终止.如果所有的顶点都有出边,则可以启动最小耗费分枝定界搜索.根的孩子(图1 6 - 5的节点B)作为第一个E-节点,在此节点上,所生成的旅行路径前缀只有一个顶点1,因此s=0, x[0]=1, x[1:n-1]是剩余的顶点(即顶点2 , 3 ,., n ).旅行路径前缀1 的开销为0 ,即c c = 0 ,并且,r c o st=n i=1M i n O u t .在程序中,bestc 给出了当前能找到的最少的耗费值.初始时,由于没有找到任何旅行路径,因此b e s t c的值被设为N o E d g e.程序旅行商问题的最小耗费分枝定界算法templateT AdjacencyWDigraph::BBTSP(int v[]){// 旅行商问题的最小耗费分枝定界算法// 定义一个最多可容纳1 0 0 0个活节点的最小堆MinHeap > H(1000);T *MinOut = new T [n+1];// 计算MinOut = 离开顶点i的最小耗费边的耗费T MinSum = 0; // 离开顶点i的最小耗费边的数目for (int i = 1; i <= n; i++) {T Min = NoEdge;for (int j = 1; j <= n; j++)if (a[j] != NoEdge &&(a[j] < Min || Min == NoEdge))Min = a[j];if (Min == NoEdge) return NoEdge; // 此路不通MinOut = Min;MinSum += Min;}// 把E-节点初始化为树根MinHeapNode E;E.x = new int [n];for (i = 0; i < n; i++)E.x = i + 1;E.s = 0; // 局部旅行路径为x [ 1 : 0 ] = 0; // 其耗费为0E.rcost = MinSum;T bestc = NoEdge; // 目前没有找到旅行路径// 搜索排列树while (E.s < n - 1) {// 不是叶子if (E.s == n - 2) {// 叶子的父节点// 通过添加两条边来完成旅行// 检查新的旅行路径是不是更好if (a[E.x[n-2]][E.x[n-1]] != NoEdge && a[E.x[n-1]][1] != NoEdge && ( + a[E.x[n-2]][E.x[n-1]] + a[E.x[n-1]][1] < bestc || bestc == NoEdge)) {// 找到更优的旅行路径bestc = + a[E.x[n-2]][E.x[n-1]] + a[E.x[n-1]][1]; = bestc;E.lcost = bestc;E . s + + ;H . I n s e r t ( E ) ; }else delete [] E.x;}else {// 产生孩子for (int i = E.s + 1; i < n; i++)if (a[E.x[E.s]][E.x] != NoEdge) {// 可行的孩子, 限定了路径的耗费T cc = + a[E.x[E.s]][E.x];T rcost = E.rcost - MinOut[E.x[E.s]];T b = cc + rcost; //下限if (b < bestc || bestc == NoEdge) {// 子树可能有更好的叶子// 把根保存到最大堆中MinHeapNode N;N.x = new int [n];for (int j = 0; j < n; j++)N.x[j] = E.x[j];N.x[E.s+1] = E.x;N.x = E.x[E.s+1]; = cc;N.s = E.s + 1;N.lcost = b;N.rcost = rcost;H . I n s e r t ( N ) ; }} // 结束可行的孩子delete [] E.x;} // 对本节点的处理结束try {H.DeleteMin(E);} // 取下一个E-节点catch (OutOfBounds) {break;} // 没有未处理的节点}if (bestc == NoEdge) return NoEdge; // 没有旅行路径// 将最优路径复制到v[1:n] 中for (i = 0; i < n; i++)v[i+1] = E.x;while (true) {//释放最小堆中的所有节点delete [] E.x;try {H.DeleteMin(E);}catch (OutOfBounds) {break;}}return bestc;}while 循环不断地展开E-节点,直到找到一个叶节点.当s = n - 1时即可说明找到了一个叶节点.旅行路径前缀是x [ 0 : n - 1 ],这个前缀中包含了有向图中所有的n个顶点.因此s = n - 1的活节点即为一个叶节点.由于算法本身的性质,在叶节点上lco st 和cc 恰好等于叶节点对应的旅行路径的耗费.由于所有剩余的活节点的lcost 值都大于等于从最小堆中取出的第一个叶节点的lcost 值,所以它们并不能帮助我们找到更好的叶节点,因此,当某个叶节点成为E-节点后,搜索过程即终止.while 循环体被分别按两种情况处理,一种是处理s = n - 2的E-节点,这时,E-节点是某个单独叶节点的父节点.如果这个叶节点对应的是一个可行的旅行路径,并且此旅行路径的耗费小于当前所能找到的最小耗费,则此叶节点被插入最小堆中,否则叶节点被删除,并开始处理下一个E-节点.其余的E-节点都放在while 循环的第二种情况中处理.首先,为每个E-节点生成它的两个子节点,由于每个E-节点代表着一条可行的路径x [ 0 : s ],因此当且仅当是有向图的边且x [ i ]是路径x [ s + 1 : n - 1 ]上的顶点时,它的子节点可行.对于每个可行的孩子节点,将边的耗费加上 即可得到此孩子节点的路径前缀( x [ 0 : s ],x) 的耗费c c.由于每个包含此前缀的旅行路径都必须包含离开每个剩余顶点的出边,因此任何叶节点对应的耗费都不可能小于cc 加上离开各剩余顶点的出边耗费的最小值之和,因而可以把这个下限值作为E-节点所生成孩子的lcost 值.如果新生成孩子的lcost 值小于目前找到的最优旅行路径的耗费b e s t c,则把新生成的孩子加入活节点队列(即最小堆)中.如果有向图没有旅行路径,程序返回N o E d g e;否则,返回最优旅行路径的耗费,而最优旅行路径的顶点序列存储在数组v 中.3.回朔法解TSP问题回朔法有"通用解题法"之称,它采用深度优先方式系统地搜索问题的所有解,基本思路是:确定解空间的组织结构之后,从根结点出发,即第一个活结点和第一个扩展结点向纵深方向转移至一个新结点,这个结点成为新的活结点,并成为当前扩展结点.如果在当前扩展结点处不能再向纵深方向转移,则当前扩展结点成为死结点.此时,回溯到最近的活结点处,并使其成为当前扩展结点,回溯到以这种工作方式递归地在解空间中搜索,直到找到所求解空间中已经无活结点为止.旅行商问题的解空间是一棵排列树.对于排列树的回溯搜索与生成1,2,……, n的所有排列的递归算法Perm类似.设开始时x=[ 1,2,… n ],则相应的排列树由x[ 1:n ]的所有排列构成.旅行商问题的回溯算法找旅行商回路的回溯算法Backtrack是类Treveling的私有成员函数,TSP是Treveling的友员.TSP(v)返回旅行售货员回路最小费用.整型数组v返回相应的回路.如果所给的图G不含旅行售货员回路,则返回NoEdge.函数TSP所作的工作主要是为调用Backtrack所需要变量初始化.由TSP调用Backtrack(2)搜索整个解空间.在递归函数Backtrack中,当i = n时,当前扩展结点是排列树的叶结点的父结点.此时,算法检测图G是否存在一条从顶点x[ n-1 ]到顶点x[ n ]的边和一条从顶点x[ n ]到顶点1的边.如果这两条边都存在,则找一条旅行售货员回路.此时,算法还需判断这条回路的费用是否优于已找到的当前最优回路的费用best.如果是,则必须更新当前最优值bestc和当前最优解bestx.当i < n时,当前扩展结点位于排列树的第i–1 层.图G中存在从顶点x[ i-1 ]到顶点x[ i ]的边时,x[ 1:i ]构成图G的一条路径,且当x[ 1:i ]的费用小于当前最优值时,算法进入排列树的第I 层.否则将剪去相应的子树.算法中用变量cc记录当前路径x[ 1:i ]的费用.解旅行商售货员问题的回溯法可描述如下:templateclass Traveling {friend Type TSP(int * *,int [],Type);private:void Backtrack(int i);int n, //图G的顶点数* x, //当前解*bestx; //当前最优解Type * *a, //图G的邻接矩阵cc, //当前费用bestc, //当前最优值NoEdge; //无边际记};templatevode Traveling::Backtrack(int i){if(I==n){if(a[x[n-1]][x[n]]! = NoEdge &&a[x[n]][1]!= NoEdge &&(cc + a[x[n-1]][x[n]]+a[x[n]][1]bestc== NoEdge) ){for(int j=1;j<=n;j++)bestx[j]=x[j];bestc =cc + a[x[n-1]][x[n]]+ a[x[n]][1];}}else {for(int j=I; j<=n;j++)//是否可进入x[j]子树if(a[x[i-1]][x[j]]! = NoEdge &&(cc + a[x[i-1]][x[i]]< bestc||bestc == NoEdge//搜索子数Swap(x[i],x[j]);cc += a[x[i-1]][x[i]];Backtrack(I+1);cc -= a[x[i-1]][x[i]];Swap(x[i],x[j]);}}}templateType TSP(Type * *a,int v[],int n,Type NoEdge){Traveling Y;//初始化YY.x = new int[n+1];// 置x为单位排列for(int i=1;i<=n;i++)Y.x[i] = I;Y.a=a;Y.n=n;Y.bestc = NoEdge;Y.bestc = v; = 0;Y. NoEdge = NoEdge;//搜索x[2:n]的全排列Y.Backtrack(2);Delete[] Y.x;三.三种方法的比较1.动态规划法和回朔法的比较:这本来就是两个完全不同的领域,一个是算法领域,一个是数据结构问题.但两者又交叉,又有区别.从本质上讲就是算法与数据结构的本质区别,回朔是一个具体的算法,动态规划是数据结构中的一个概念.动态规划讲究的是状态的转化,以状态为基准,确定算法,动态规划法所针对的问题有一个显著的特征,即它所对应的子问题树中的子问题呈现大量的重复.动态规划法的关键就在于,对于重复出现的子问题,只在第一次遇到时加以求解,并把答案保存起来,让以后再遇到时直接引用,不必重新求解.简单的说就是:动态规划法是从小单元开始积累计算结果.回朔讲究过程的推进与反还,随数据的搜索,标记,确定下一步的行进方向,回朔是去搜索. 如果想要搜索时,发现有很多重复计算,就应该想到用动态规划了.动态规划和搜索都可以解决具有最优子结构的问题,然而动态规划在解决子问题的时候不重复计算已经计算过的子问题,对每个子问题只计算一次;而简单的搜索则递归地计算所有遇到的的子问题.比如一个问题的搜索树具有如下形式:........A......./.......B...C...../.\./.....D...E...F如果使用一般深度优先的搜索,依次搜索的顺序是A-B-D-E-C-E-F,注意其中节点E被重复搜索了两次;如果每个节点看作是一个子问题的话,节点E所代表的子问题就被重复计算了两次; 但是如果是用动态规划,按照树的层次划分阶段,按照自底向上的顺序,则在第一阶段计算D,E,F;第二阶段计算B,C;第三阶段计算A;这样就没有重复计算子问题E.搜索法的优点是实现方便,缺点是在子问题有大量的重复的时候要重复计算子问题,效率较低;动态规划虽然效率高,但是阶段的划分和状态的表示比较复杂,另外,搜索的时候只要保存单前的结点;而动态规划则至少要保存上一个阶段的所有节点,比如在动态规划进行到第2阶段的时候,必须把第三阶段的D,E,F三个节点全部保存起来,所以动态规划是用空间换时间.另外,有一种折衷的办法,就是备忘录法,这是动态规划的一种变形.该方法的思想是:按照一般的搜索算法解决子问题,但是用一个表将所有解决过的子问题保存起来,遇到一个子问题的时候,先查表看是否是已经解决过的,如果已解决过了就不用重复计算.比如搜索上面那棵树,在A-B-D-E的时候,已经将E记录在表里了,等到了A-B-D-E-C的时候,发现E已经被搜索过,就不再搜索E,而直接搜索F,因此备忘录法的搜索顺序是A-B-D-E-C-(跳过E)-F自底向上的动态规划还有一个缺点,比如对于下面的树:........A......./.......B...C......G...../.\./.\..../.....D...E...F..H (I)如用自底向上的动态规划,各个阶段搜索的节点依次是:D,E,F,H,IB,C,GAA才是我们最终要解决的问题,可以看到,G,H,I根本与问题A无关,但是动态规划还是将它们也解决了一遍,这就造成了效率降低.而备忘录法则可以避免这种问题,按照备忘录法,搜索的次序仍然是:A-B-D-E-C-(跳过E)-F.备忘录法的优点是实现简单,且在子问题空间中存在大量冗余子问题的时候效率较高;但是要占用较大的内存空间(需要开一个很大的表来记录已经解决的子问题),而且如果用递归实现的话递归压栈出栈也会影响效率;而自底向上的动态规划一般用for循环就可以了.值得一提的是,用动态规划法来计算旅行商的时间复杂度是指数型的.2. 分支限界法和回朔法的比较:分支限界法类似于回溯法,也是一种在问题的解空间树T上搜索问题解的算法.但在一般情况下,分支限界与回溯法的求解目标不同.回溯法的求解目标是找出T中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解.我们先看一个列子:设G=(V,E)是一个带权图.图1中各边的费用(权)为一正数.图中的一条周游线是包括V中的每个顶点在内的一条回路.一条周游路线的费用是这条路线上所有边的费用之和.所谓旅行售货员问题就是要在图G中找出一条有最小费用的周游路线.给定一个有n个顶点的带权图G,旅行售货员问题要找出图G的费用(权)最小的周游路线.图1是一个4顶点无向带权图.顶点序列1,2,4,3,1;1,3,2,4,1和1,4,3,2,1是该图中3条不同的周游路线.1 256 1043 20 4图1 4顶点带权图该问题的解空间可以组织成一棵树,从树的根结点到任一叶结点的路径定义了图G的一条周游路线.图1是当n=4时这种树结构的示例.其中从根结点A到叶结点L的路径上边的标号组成一条周游路线1,2,3,4,1.而从根结点到叶结点O的路径则表示周游路线1,3,4,2,1.图G的每一条周游路线都恰好对应解空间树中一条从根结点到叶结点的路径.因此,解空间树中叶结点个数为(n-1)!.A1B2 3 4C D E3 24 2 3F G H I J K4 3 4 2 3 2L M N O P Q图2 旅行售货员问题的解空间树对于图1中的图G,用回溯法找最小费用周游路线时,从解空间树的根结点A出发,搜索至B,C,F,L.在叶结点L处记录找到的周游路线1,2,3,4,1,该周游路线的费用为59.从叶结点L返回至最近活动结点F处.由于F处已没有可扩展结点,算法又返回到结点C处.结点C成为新扩展结点,由新扩展结点,算法再移至结点G 后又移至结点M,得到周游路线1,2,4,3,1,其费用为66.这个费用不比已有周游路线1,2,3,4,1的费用小.因此,舍弃该结点.算法有依次返回至结点G,C,B.从结点B,算法继续搜索至结点D,H,N.在叶结点N算法返回至结点H,D,然后再从结点D开始继续向纵深搜索至结点O.依次方式算法继续搜索遍整个解空间,最终得到1,3,2,4,1是一条最小费用周游路线.以上便是回溯法找最小费用周游路线的实列,但如果我们用分支限界法来解的话,会更适合.由于求解目标不同,导致分支限界法与回溯法在解空间树T上的搜索方式也不相同.回溯法以深度优先的方式搜索解空间树T,而分支限界法则以广度优先或以最小消耗优先的方式搜索解空间树T.分支限界法的搜索策略是,在扩展结点处,先生成所有的儿子结点(分支),然后再从当前的活动点表中选择下一个扩展结点.为了有效地选择下一扩展结点,以加速搜索的进程,在每一活结点处,计算一个函数值(限界),并根据这些已计算出的函数值,从当前活结点表中选择一个最有利的结点作为扩展结点,使搜索朝着解空间树上的最优解的分支推进,以便尽快的找出一个最优解.四.结论:参考文献:动态规划dynamic programming图片:图片:图片:图片:图片:图片:图片:图片:图片:图片:图片:图片:图片:dongtai guihua动态规划(卷名:自动控制与系统工程)dynamic programming研究多段(多步)决策过程最优化问题的一种数学方法,英文缩写DP,是最优控制和运筹学的重要数学工具。

动态规划法-回溯法-分支限界法求解TSP问题实验报告

动态规划法-回溯法-分支限界法求解TSP问题实验报告

动态规划法-回溯法-分支限界法求解TSP问题实验报告TSP问题算法实验报告指导教师:季晓慧姓名:辛瑞乾学号: 1004131114 提交日期: 2015年11月目录总述 (4)动态规划法 (4)算法问题分析 (4)算法设计 (5)实现代码 (6)输入输出截图 (10)OJ提交截图 (10)算法优化分析 (10)回溯法 (11)算法问题分析 (11)算法设计 (11)实现代码 (12)输入输出截图 (17)OJ提交截图 (17)算法优化分析 (17)分支限界法 (18)算法问题分析 (18)算法设计 (19)实现代码 (20)输入输出截图 (29)OJ提交截图 (29)算法优化分析 (29)总结 (30)总述TSP问题又称为旅行商问题,是指一个旅行商要历经所有城市一次最后又回到原来的城市,求最短路程或最小花费,解决TSP可以用好多算法,比如蛮力法,动态规划法…具体的时间复杂的也各有差异,本次实验报告包含动态规划法,回溯法以及分支限界法。

动态规划法算法问题分析假设n个顶点分别用0~n-1的数字编号,顶点之间的代价存放在数组mp[n][n]中,下面考虑从顶点0出发求解TSP问题的填表形式。

首先,按个数为1、2、…、n-1的顺序生成1~n-1个元素的子集存放在数组x[2^n-1]中,例如当n=4时,x[1]={1},x[2]={2},x[3]={3},x[4]={1,2},x[5 ]={1,3},x[6]={2,3},x[7]={1,2,3}。

设数组dp[n][2^n-1]存放迭代结果,其中dp[i][j]表示从顶点i经过子集x[j]中的顶点一次且一次,最后回到出发点0的最短路径长度,动态规划法求解TSP问题的算法如下。

算法设计输入:图的代价矩阵mp[n][n]输出:从顶点0出发经过所有顶点一次且仅一次再回到顶点0的最短路径长度1.初始化第0列(动态规划的边界问题)for(i=1;i<n;i++)dp[i][0]=mp[i][0]2.依次处理每个子集数组x[2^n-1]for(i=1;i<n;i++)if(子集x[j]中不包含i)对x[j]中的每个元素k,计算d[i][j]=min{mp[i][k]+dp[k][j-1]};3.输出最短路径长度。

动态规划法,回溯法,分支限界法求解TSP问题实验报告

动态规划法,回溯法,分支限界法求解TSP问题实验报告
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
using namespace std;
int mp[20][20];
int x[30],vis[30];
int n,k,cur,ans;
void init()
{
for(int i=0;i<n;i++)
{
mp[i][j]=inf;
continue;
}
int tmp;
scanf("%d",&tmp);
mp[i][j]=tmp;
}
}
int mx=(1<<(n-1));
dp[0][0]=0;
for(int i=1; i<n; i++)
{
dp[i][0]=mp[i][0];
}
dp[0][mx-1]=inf;
实现代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
算法设计
输入:图的代价矩阵mp[n][n]
输出:从顶点0出发经过所有顶点一次且仅一次再回到顶点0的最短路径长度

动态规划法,回溯法,分支限界法求解TSP问题实验报告

动态规划法,回溯法,分支限界法求解TSP问题实验报告

TSP问题算法实验报告指导教师:季晓慧姓名:辛瑞乾学号:提交日期: 2015年11月目录总述...................................................................... 动态规划法................................................................算法问题分析............................................................算法设计................................................................实现代码................................................................输入输出截图............................................................OJ提交截图..............................................................算法优化分析............................................................ 回溯法....................................................................算法问题分析............................................................算法设计................................................................实现代码................................................................输入输出截图............................................................OJ提交截图..............................................................算法优化分析............................................................ 分支限界法................................................................算法问题分析............................................................算法设计................................................................实现代码................................................................输入输出截图............................................................OJ提交截图..............................................................算法优化分析............................................................总结......................................................................总述TSP问题又称为旅行商问题,是指一个旅行商要历经所有城市一次最后又回到原来的城市,求最短路程或最小花费,解决TSP可以用好多算法,比如蛮力法,动态规划法…具体的时间复杂的也各有差异,本次实验报告包含动态规划法,回溯法以及分支限界法。

TSP问题求解实验报告

TSP问题求解实验报告

TSP问题求解(一)实验目的熟悉和掌握遗传算法的原理,流程和编码策略,并利用遗传求解函数优化问题,理解求解TSP问题的流程并测试主要参数对结果的影响。

(二)实验原理巡回旅行商问题给定一组n个城市和俩俩之间的直达距离,寻找一条闭合的旅程,使得每个城市刚好经过一次且总的旅行距离最短。

TSP问题也称为货郎担问题,是一个古老的问题。

最早可以追溯到1759年Euler提出的骑士旅行的问题。

1948年,由美国兰德公司推动,TSP成为近代组合优化领域的典型难题。

TSP是一个具有广泛的应用背景和重要理论价值的组合优化问题。

近年来,有很多解决该问题的较为有效的算法不断被推出,例如Hopfield神经网络方法,模拟退火方法以及遗传算法方法等。

TSP搜索空间随着城市数n的增加而增大,所有的旅程路线组合数为(n-1)!/2。

在如此庞大的搜索空间中寻求最优解,对于常规方法和现有的计算工具而言,存在着诸多计算困难。

借助遗传算法的搜索能力解决TSP问题,是很自然的想法。

基本遗传算法可定义为一个8元组:(SGA)=(C,E,P0,M,Φ,Г,Ψ,Τ)C ——个体的编码方法,SGA使用固定长度二进制符号串编码方法;E ——个体的适应度评价函数;P0——初始群体;M ——群体大小,一般取20—100;Ф——选择算子,SGA使用比例算子;Г——交叉算子,SGA使用单点交叉算子;Ψ——变异算子,SGA使用基本位变异算子;Т——算法终止条件,一般终止进化代数为100—500;问题的表示对于一个实际的待优化问题,首先需要将其表示为适合于遗传算法操作的形式。

用遗传算法解决TSP,一个旅程很自然的表示为n个城市的排列,但基于二进制编码的交叉和变异操作不能适用。

路径表示是表示旅程对应的基因编码的最自然,最简单的表示方法。

它在编码,解码,存储过程中相对容易理解和实现。

例如:旅程(5-1-7-8-9-4-6-2-3)可以直接表示为(5 1 7 8 9 4 6 2 3)(三)实验内容N>=8。

分支限界法——TSP问题

分支限界法——TSP问题

while(E.s < n - 1) {//非叶结点 if(E.s == n - 2){//当前扩展结点是叶结点的父结点 //再加2条边构成回路 所构成回路是否优于当前最优解 if(a[E.x[n - 2]][E.[n - 1]] != NoEdge && a[E.x[n - 1]][1] != NoEdge && ( +a[E.x[n - 2]][E.x[n - 1]] + a[E.x[n - 1]][1] < bestc || bestc == NoEdge)) {//费用更小的回路 bestc = + a[E.x[n - 2]][E.x[n - 1]] + a[E.x[n - 1]]; = bestc; E.lcost = bestc; E.s++; H.Insert(E); } else delete[]E.x; }//舍弃扩展结点 else {//产生当前扩展结点的儿子结点 for(int i = E.s + 1; i < n; i++) if(a[E.x[E.s]][E.x[i]] != NoEdge) { //可行儿子结点 Type cc = + a[E.x[E.s]][E.x[i]]; Type rcost = E.rcost - MinOut[E.x[E.s]]; Type b = cc + rcost; //下界
算法中while循环的终止条件是排列树的一个叶结点成为 当前扩展结点。当s=n-1时,已找到的回路前缀是x[0:n1],它已包含图G的所有n个顶点。因此,当s=n-1时,相 应的扩展结点表示一个叶结点。此时该叶结点所相应的回 路的费用等于cc和lcost的值。剩余的活结点的lcost值不 小于已找到的回路的费用。它们都不可能导致费用更小的 回路。因此已找到叶结点所相应的回路是一个最小费用旅 行售货员回路,算法可结束。 算法结束时返回找到的最小费用,相应的最优解由数组v 给出。

回溯法求解TSP问题

回溯法求解TSP问题

回溯法求解T S P问题-CAL-FENGHAI-(2020YEAR-YICAI)_JINGBIAN人工智能实验报告实验名称:TSP问题姓名:xxx学号:xxxxx大学计算机学院2014年1月14日一.实验目的掌握递归回溯法的思想,能够求解TSP 问题,增强自己的编程能力.二.实验内容下图是5个城市的交通图,城市之间的连线权重表示城市之间路程的费用。

要求从A 城出发,经过其它城市一次且仅一次,最后回到A 城,找出一条费用最低的回路。

请用伪代码形式描述所设计的算法。

BDE三、回溯法思想: 回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标。

但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

若已有满足约束条件的部分解,不妨设为(x1,x2,x3,……xi ),I<n,则添加x(i+1)属于s(i+2),检查 (x1,x2,……,xi,x(i+1))是否满足条件,满足了就继续添加x(i+2)、s(i+2),若所有的x(i+1)属于s(i+1)都不能得到 部分解,就去掉xi ,回溯到(xi,x2,……x(i- 1)),添加那些未考察过的x1属于s1,看其是否满足约束条件,为此反复进行,直至得到解或证明无解。

四、算法流程:五、关键技术:1、使用了递归回溯法,通过递归调用,节省了代码量,使代码更简洁易懂。

关键代码:void Backtracking(int cityId, int depth, int len) { ize(); i++) { econd] == false) {econd] = true;pre[tab[cityId][i].second] = cityId;Backtracking(tab[cityId][i].second, depth + 1, len +tab[cityId][i].first); econd] = -1;econd] = false; ush_back(PII(w, v));ush_back(PII(w, u)); ush_back(PII(w, v));tab[nodeId][i].first tab[nodeId][i].second六、实验心得1、重温了算法课程里面学过的回溯法,强化了这种编程思想。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

TSP问题算法实验报告指导教师:****名:***学号:**********提交日期:2015年11月目录总述 (2)动态规划法 (3)算法问题分析 (3)算法设计 (3)实现代码 (3)输入输出截图 (6)OJ提交截图 (6)算法优化分析 (6)回溯法 (6)算法问题分析 (6)算法设计 (7)实现代码 (7)输入输出截图 (9)OJ提交截图 (9)算法优化分析 (10)分支限界法 (10)算法问题分析 (10)算法设计 (10)实现代码 (10)输入输出截图 (15)OJ提交截图 (15)算法优化分析 (15)总结 (16)总述TSP问题又称为旅行商问题,是指一个旅行商要历经所有城市一次最后又回到原来的城市,求最短路程或最小花费,解决TSP可以用好多算法,比如蛮力法,动态规划法…具体的时间复杂的也各有差异,本次实验报告包含动态规划法,回溯法以及分支限界法。

动态规划法算法问题分析假设n个顶点分别用0~n-1的数字编号,顶点之间的代价存放在数组mp[n][n]中,下面考虑从顶点0出发求解TSP问题的填表形式。

首先,按个数为1、2、…、n-1的顺序生成1~n-1个元素的子集存放在数组x[2^n-1]中,例如当n=4时,x[1]={1},x[2]={2},x[3]={3},x[4]={1,2},x[5]={1,3},x[6]={2,3},x[7]={1,2,3}。

设数组dp[n][2^n-1]存放迭代结果,其中dp[i][j]表示从顶点i经过子集x[j]中的顶点一次且一次,最后回到出发点0的最短路径长度,动态规划法求解TSP问题的算法如下。

算法设计输入:图的代价矩阵mp[n][n]输出:从顶点0出发经过所有顶点一次且仅一次再回到顶点0的最短路径长度1.初始化第0列(动态规划的边界问题)for(i=1;i<n;i++)dp[i][0]=mp[i][0]2.依次处理每个子集数组x[2^n-1]for(i=1;i<n;i++)if(子集x[j]中不包含i)对x[j]中的每个元素k,计算d[i][j]=min{mp[i][k]+dp[k][j-1]};3.输出最短路径长度。

实现代码#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <ctime>#include <iostream>#include <algorithm>#include <string>#include <vector>#include <deque>#include <list>#include <set>#include <map>#include <stack>#include <queue>#include <cctype>#include <numeric>#include <iomanip>#include <bitset>#include <sstream>#include <fstream>#define debug "output for debug\n" #define pi (acos(-1.0))#define eps (1e-8)#define inf 0x3f3f3f3f#define ll long long int#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1 using namespace std;const int mod = 1000000007;const int Max = 100005;int n,mp[20][20],dp[20][40000];int main(){while(~scanf("%d",&n)){int ans=inf;memset(mp,0,sizeof mp);for(int i=0; i<n; i++){for(int j=0; j<n; j++){if(i==j){mp[i][j]=inf;continue;}int tmp;scanf("%d",&tmp);mp[i][j]=tmp;}}int mx=(1<<(n-1));dp[0][0]=0;for(int i=1; i<n; i++){dp[i][0]=mp[i][0];}dp[0][mx-1]=inf;for(int j=1; j<(mx-1); j++){for(int i=1; i<n; i++){if((j&(1<<(i-1)))==0){int x,y=inf;for(int k=1; k<n; k++){if((j&(1<<(k-1)))>0){x=dp[k][(j-(1<<(k-1)))]+mp[i][k];y=min(y,x);}}dp[i][j]=y;}}}dp[0][mx-1]=inf;for(int i=1;i<n;i++)dp[0][mx-1]=min(dp[0][mx-1],mp[0][i]+dp[i][(mx-1)-(1<<(i-1))]);printf("%d\n",dp[0][mx-1]);}return 0;}输入输出截图OJ提交截图算法优化分析该算法需要对顶点集合{1,2,…,n-1}的每一个子集进行操作,因此时间复杂度为O(2^n)。

和蛮力法相比,动态规划法求解TSP问题,把原来的时间复杂度是O(n!)的排列问题,转化为组合问题,从而降低了算法的时间复杂度,但仍需要指数时间。

回溯法算法问题分析回溯法求解TSP问题,首先把所有的顶点的访问标志初始化为0,然后在解空间树中从根节点出发开始搜索,如果从根节点到当前结点对应一个部分解,即满足上述约束条件,则在当前结点处选择第一棵子树继续搜索,否则,对当前子树的兄弟结点进行搜索,如果当前结点的所有子树都已尝试过并且发生冲突,则回溯到当前结点的父节点。

采用邻接矩阵mp[n][n]存储顶点之间边的情况,为避免在函数间传递参数,将数组mp设置为全局变量,设数组x[n]表示哈密顿回路经过的顶点。

算法设计输入:无向图G=(V,E)输出:哈密顿回路1、将顶点数组x[n]初始化为0,标志数组vis[n]初始化为0;2、从顶点0出发构造哈密顿回路:vis[0]=1;x[0]=1;k=1;3、While(k>=1)3.1、x[k]=x[k]+1,搜索下一个顶点。

3.2、若n个顶点没有被穷举完,则执行下列操作3.2.1、若顶点x[k]不在湖密顿回路上并且(x[k-1],x[k])∈E,转步骤3.3;3.2.2、否则,x[k]=x[k]+1,搜索下一个顶点。

3.3、若数组x[n]已经形成哈密顿路径,则输出数组x[n],算法结束;3.4、若数组x[n]构成哈密顿路径的部分解,则k=k+1,转步骤3;3.5、否则,取消顶点x[k]的访问标志,重置x[k],k=k-1,转步骤3。

实现代码#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <ctime>#include <iostream>#include <algorithm>#include <string>#include <vector>#include <deque>#include <list>#include <set>#include <map>#include <stack>#include <queue>#include <cctype>#include <numeric>#include <iomanip>#include <bitset>#include <sstream>#include <fstream>#define debug "output for debug\n"#define pi (acos(-1.0))#define eps (1e-8)#define inf 0x3f3f3f3f#define ll long long int#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1using namespace std;int mp[20][20];int x[30],vis[30];int n,k,cur,ans;void init(){for(int i=0;i<n;i++)for(int j=0;j<n;j++)mp[i][j]=-1;ans=-1;cur=0;for(int i=1;i<=n;i++)x[i]=i;}void dfs(int t){if(t==n){if(mp[x[n-1]][x[n]]!=-1&&(mp[x[n]][1]!=-1)&&(cur+mp[x[n-1]][x[n]]+mp[x[n]][1]<ans||ans==-1)) {for(int i=1;i<=n;i++)vis[i]=x[i];ans=cur+mp[x[n-1]][x[n]]+mp[x[n]][1];}}else{for(int i=t;i<=n;i++){if(mp[x[t-1]][x[i]]!=-1&&(cur+mp[x[t-1]][x[i]]<ans||ans==-1)){swap(x[t],x[i]);cur+=mp[x[t-1]][x[t]];dfs(t+1);cur-=mp[x[t-1]][x[t]];swap(x[t],x[i]);}}}}int main(){while(~scanf("%d",&n)){init();for(int i=1; i<=n; i++){for(int j=1; j<=n; j++){if(i==j)continue;scanf("%d",&mp[i][j]);}}///puts("YES");dfs(2);cout<<ans<<endl;}return 0;}输入输出截图OJ提交截图算法优化分析在哈密顿回路的可能解中,考虑到约束条件xi!=xj(1<=I,j<=n,i!=j),则可能解应该是(1,2,…,n)的一个排列,对应的解空间树种至少有n!个叶子结点,每个叶子结点代表一种可能解。

相关文档
最新文档