【分支限界法】求解TSP问题

本文通过实例详细介绍了如何运用分支限界法来求解旅行商问题(TSP)。首先阐述了TSP问题的基本描述,接着提出了求解思路,通过计算目标函数的上界和下界来指导搜索过程。然后,展示了分支限界法的具体搜索步骤,最终找到了TSP问题的一个最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

TSP问题是指旅行家要旅行n个城市,要求各个城市经历且仅经历一次然后回到出发城市,并要求所走的路程最短。
在这里插入图片描述

求解思路

  采用贪心法求得近似解为1→3→5→4→2→1,其路径长度为1+2+3+7+3=16,这可以作为TSP问题的上界。
  把矩阵中每一行最小的元素相加,可以得到一个简单的下界,其路径长度为1+3+1+3+2=10,但是还有一个信息量更大的下界:考虑一个TSP问题的完整解,在每条路径上,每个城市都有两条邻接边,一条是进入这个城市的,另一条是离开这个城市的,那么,如果把矩阵中每一行最小的两个元素相加再除以2,如果图中所有的代价都是整数,再对这个结果向上取整,就得到了一个合理的下界。
  lb=((1+3)+(3+6)+(1+2)+(3+4)+(2+3))/2=14
  于是,得到了目标函数的界[14, 16]。
  需要强调的是,这个解并不是一个合法的选择(可能没有构成哈密顿回路),它仅仅给出了一个参考下界。
部分解的目标函数值的计算方法
  例如图所示无向图,如果部分解包含边(1, 3,5),则该部分解的下界是lb=(2*(1+2)+3+3+(3+6)+(3+4))/2=14。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  应用分支限界法求解图9.4所示无向图的TSP问题,其搜索空间如图9.5所示,具体的搜索过程如下(加黑表示该路径上已经确定的边):
(1)在根结点1,根据限界函数计算目标函数的值为lb=((1+3)+(3+6)+(1+2)+(3+4)+(2+3))/2=14;
(2)在结点2,从城市1到城市2,路径长度为3,目标函数的值为(23)+1+6+(1+2)+(3+4)+(2+3))/2=14,将结点2加入待处理结点表PT中;在结点3,从城市1到城市3,路径长度为1,目标函数的值为(21+1+1+(3+6)+(3+4)+(2+3))/2=14,将结点3加入表PT中;在结点4,从城市1到城市4,路径长度为5,目标函数的值为((2*5)+1+3+(3+6)+(1+2)+(2+3))/2=16,将结点4加入表PT中;在结点5,从城市1到城市5,路径长度为8,目标函数的值为((1+8)+(3+6)+(1+2)+(3+5)+(2+8))/2=19,超出目标函数的界,将结点5丢弃;
(3)在表PT中选取目标函数值极小的结点2优先进行搜索;
(4)在结点6,从城市2到城市3,目标函数值为((1+3)+(3+6)+(1+6)+(3+4)+(2+3))/2=16,将结点6加入表PT中;在结点7,从城市2到城市4,目标函数值为((1+3)+(3+7)+(1+2)+(3+7)+(2+3))/2=16,将结点7加入表PT中;在结点8,从城市2到城市5,目标函数值为
((1+3)+(3+9)+(1+2)+(3+4)+(2+9))/2=19,超出目标函数的界,将结点8丢弃;
(5)在表PT中选取目标函数值极小的结点3优先进行搜索;
(6)在结点9,从城市3到城市2,目标函数值为((1+3)+(3+6)+(1+6)+(3+4)+(2+3))/2=16,将结点9加入表PT中;在结点10,从城市3到城市4,目标函数值为((1+3)+(3+6)+(1+4)+(3+4)+(2+3))/2=15,将结点10加入表PT中;在结点11,从城市3到城市5,目标函数值为((1+3)+(3+6)+(1+2)+(3+4)+(2+3))/2=14,将结点11加入表PT中;
(7)在表PT中选取目标函数值极小的结点11优先进行搜索;
(8)在结点12,从城市5到城市2,目标函数值为((1+3)+(3+9)+(1+2)+(3+4)+(2+9))/2=19,超出目标函数的界,将结点12丢弃;在结点13,从城市5到城市4,目标函数值为((1+3)+(3+6)+(1+2)+(3+4)+(2+3))/2=14,将结点13
加入表PT中;
(9)在表PT中选取目标函数值极小的结点13优先进行搜索;
(10)在结点14,从城市4到城市2,目标函数值为((1+3)+(3+7)+(1+2)+(3+7)+(2+3))/2=16,最后从城市2回到城市1,目标函数值为((1+3)+(3+7)+(1+2)+(3+7)+(2+3))/2=16,由于结点14为叶子结点,得到一个可行解,其路径长度为16;
(11)在表PT中选取目标函数值极小的结点10优先进行搜索;
(12)在结点15,从城市4到城市2,目标函数的值为((1+3)+(3+7)+(1+4)+(7+4)+(2+3))/2=18,超出目标函数的界,将结点15丢弃;在结点16,从城市4到城市5,目标函数值为((1+3)+(3+6)+(1+4)+(3+4)+(2+3))/2=15,将结点16加入表PT中;
(13)在表PT中选取目标函数值极小的结点16优先进行搜索;
(14)在结点17,从城市5到城市2,目标函数的值为((1+3)+(3+9)+(1+4)+(3+4)+(9+3))/2=20,超出目标函数的界,将结点17丢弃;
(15)表PT中目标函数值均为16,且有一个是叶子结点14,所以,结点14对应的解1→3→5→4→2→1 即是TSP问题的最优解,搜索过程结束。
在这里插入图片描述在这里插入图片描述

代码实现

/*分支限界法求解TSP问题
*/
#include<iostream>
#include<algorithm>
#include<queue>
#define MAXLENGTH 10
using namespace std;

//城市个数
int n;
//城市距离代价矩阵
int value[MAXLENGTH][MAXLENGTH];
//定义访问标识符
bool dfs_visited[MAXLENGTH];
//定义函数上界
int up;
//定义下界
int down;
//距离修正函数声明
void Modify();
//分支限界法求解TSP问题
int solve();
//贪心法计算上界
void get_up();
//计算下界
void get_down();
//贪心算法
int dfs(int, int, int);
//待处理节点表
struct  Node
{
   
   
	//节点访问标记
	bool visited[MAXLENGTH];
	//访问次序
	int cixu[MAXLENGTH];
	//第一个点
	int start;
	//第一个节点的邻接节点
	int start_p;
	//最后一个节点
	int end;
	//最后一个节点的邻接节点
	int end_p;
	//走过的点数
	int k;
	//经过路径的距离
	int sumv;
	//目标函数值
	int lb;
	//运算符重载
	//目标函数值小的先出队列
	bool operator <(const Node &p) const{
   
   
		return p.lb < lb;
	}
};

Node tmp;
//int number[20];

int result[MAXLENGTH];
int times=0;
//计算目标函数值
int get_lb(Node);
//建立一个优先队列
priority_queue<Node> pq;

int main(
支限界法类又称为剪枝限界法或分支定界法,它类似于回溯法,也是一种在问题的解空间树T上搜索问题解的算法。它与回溯法有两点不同:①回溯法只通过约束条件剪去非可行解,而分支限界法不仅通过约束条件,而且通过目标函数的限界来减少无效搜索,也就是剪掉了某些不包含最优解的可行解。②在解空间树上的搜索方式也不相同。回溯法以深度优先的方式搜索解空间树,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树。分支限界法的搜索策略是:在扩展结点处,先生成其所有的儿子结点(分支),然后再从当前的活结点表中选择下一个扩展结点。为了有效地选择下一扩展结点,以加速搜索的进程, 在每一活结点处,计算一个函数值(限界),并根据这些已计算出的函数值,从当前活结点表中选择一个最有利的结点作为扩展结点,使搜索朝着解空间树上有最优解的分支推进,以便尽快地找出一个最优解。 从活结点表中选择下一扩展结点的不同方式导致不同的分支限界法。最常见的有以下两种方式: ①队列式(FIFO)分支限界法:队列式分支限界法将活结点表组织成一个队列,并按队列的先进先出原则选取下一个结点为当前扩展结点。 ②优先队列式分支限界法:优先队列式分支限界法将活结点表按照某个估值函数C(x)的值组织成一个优先队列,并按优先队列中规定的结点优先级选取优先级最高的下一个结点成为当前扩展结点。 影响分支限界法搜索效率的有两个主要因素:一是优先队列Q的优先级由C(x)确定,它能否保证在尽可能早的情况下找到最优解,如果一开始找到的就是最优解,那么搜索的空间就能降低到最小。二是限界函数u(x),它越严格就越可能多地剪去分支,从而减少搜索空间。 在用分支限界法解决TSP问题时,有不少很好的限界函数估值函数已经构造出来出了(限于篇幅,这里不做详细介绍), 使得分支限界法在大多数情况下的搜索效率大大高于回溯法。但是,在最坏情况下,该算法的时间复杂度仍然是O(n!),而且有可能所有的(n-1)!个结点都要存储在队列中。 近似算法是指不能肯定找到最优解的算法,但通常找到的也是比较好的解,或称近似最优解。[20]一般而言,近似算法的时间复杂度较低,通常都是多项式时间内的。由于近似算法的时间效率高,所以在实际应用中,主要是使用近似算法,这一类算法也一直是研究的主要对象。传统的近似算法以采用贪心策略局部搜索为主,而几十年来,随着以遗传算法为代表的新型启发式搜索算法的逐步完善,在解决TSP问题上获得了巨大的成功。遗传算法、模拟退火算法、蚁群算法等已经成为公认的好算法。在本节中,将介绍传统的近似算法。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值