优先队列式_分支限界法_TSP旅行商问题问题

最近真的好久没有更了,会陆续更一些算法问题,有需要的朋友请查看哦!欢迎大家与我交流~
一起学习一起进步哦~
问题:
某售货员要去n个城市推销商品,该售货员从一个城市出发,经过每个城市一次,最后回到起始城市。应如何选择行进路线,以使总的路程最短。设n=4, 城市与城市之间的费用如图所示。采用优先队列式分支限界算法解决该问题。
在这里插入图片描述import java.util.Scanner;

public class BBTSP {
//排列树结点描述类
private static class HeapNode implements Comparable
{ int s; //s 表示结点在排列树中的层次,根结点到当前结点的路径为x[0:s]
float lcost; //子树费用的下界
float cc; //当前费用
float rcost; //x[s:n-1]中顶点最小出边费用和
int [ ] x; //需要进一步搜索的顶点是x[s+1, n-1]
//构造方法
HeapNode(float lc,float ccc,float rc,int ss,int [ ]xx)
{ lcost=lc;
cc=ccc;
rcost=rc;
s=ss;
x=xx;
}
@Override
public int compareTo(Object o) {

	return 0;
}
  }

//图G的邻接矩阵
static float [ ][ ]a;
static int n;

//最小堆描述
public static class MinHeap{
static HeapNode[] h;//活结点表
private static int front;//堆顶引用,若堆不空,指向堆顶元素
private static int rear;//堆尾引用,若堆不空,指向堆尾元素的下一个位置
public MinHeap(HeapNode[] h,int a,int b) {
front=rear=0;
this.h=h;
}

 //筛选法调整堆
 //将以low为根结点的子树调整成小顶堆,low和high分别是待调整序列的上界和下界
 static void sift(int low,int high) {
	 int i=low;//子树的根结点
	 int j=2*i+1;//j为i结点的左孩子
	 HeapNode temp=h[i];
	 while(j<high) {//沿较小值的孩子结点向下筛选
		 if(j<high-1&&h[j].lcost>h[j+1].lcost) {
			 j++;//结点优先级进行比较,j为左右孩子结点的较小者
		 }
		 if(temp.lcost>h[j].lcost) {//若父母结点值较大
			 h[i]=h[j];//孩子结点的较小者上移
			 i=j;
			 j=2*j+1;//对以被交换的子结点作为根结点所在的子树进行调整
		 }else {
			 j=high+1;//退出循环
		 }
	 }
	 h[i]=temp;//当前子树的原根值调整后的位置
 }

 //创建堆算法
 static void insertheapSort() {
	 int n=rear-front;//待加入堆的结点个数
	 HeapNode temp;
	 for(int i=n/2-1;i>=front;i--) {//创建堆
		 sift(i,n);
	 }
 }
 
 
//取出堆顶元素,并且重新调整堆为最大堆的算法
 static HeapNode removeheapSort() {
	 int n=rear-front;//
	 int i=n-1;//堆的最后一个结点
	 HeapNode temp=h[front];
	 h[front]=h[i];//将堆中最大关键字值移到最前面
	 sift(front,i);//并且调整成堆
	 return temp;//返回最顶堆结点 
 }
//将堆元素node加入堆,并且调整堆
public void insert(HeapNode node) {
	h[rear]=node;
	 rear+=1;//修改尾指针
	 insertheapSort();//调整堆
}
public HeapNode removemin() {
	HeapNode temp=removeheapSort();
	rear-=1;
	return temp;
	
}

}
//求出这棵树的minsum
public static float bbTSP(int[] v)
{ //解货郎担问题的优先队列式分支限界法
HeapNode []h1=new HeapNode[n+1];
MinHeap heap=new MinHeap(h1,0,n+1);//最小堆
//minOut[i]=顶点i的最小出边费用
float [] minOut=new float[n+1];
float minSum=0;//最小出边费用和
for(int i=1;i<=n;i++)
{//计算minOut[i]和minSum
float min=Float.MAX_VALUE;
for(int j=1;j<=n;j++)
if(a[i][j]>0 && a[i][j]<min)
min=a[i][j];
if(min==Float.MAX_VALUE) return Float.MAX_VALUE;//无回路
minOut[i]=min;
minSum+=min;
}
//各个变量初始化
int [ ]x=new int[n];
for(int i=0;i<n;i++)x[i]=i+1;
HeapNode enode=new HeapNode(0,0,minSum,0,x);
float bestc=Float.MAX_VALUE;

//搜索排列树
while(enode!=null && enode.s<n-1) //非叶结点(内部节点)
{x=enode.x;
if(enode.s==n-2) //当前扩展结点是叶结点的父结点 ,再加2条边构成回路
//所构成回路是否优于当前最优解
{if(a[x[n-2]][x[n-1]]>0 && a[x[n-1]][1]>0 &&
enode.cc+a[x[n-2]][x[n-1]]+a[x[n-1]][1]<bestc) //找到费用更小的回路
{ bestc=enode.cc+a[x[n-2]][x[n-1]]+a[x[n-1]][1];
enode.cc=bestc;
enode.lcost=bestc;
enode.s++;
heap.insert(enode);
}
}
else
{ //产生当前扩展结点的儿子结点
for(int i=enode.s+1;i<n;i++)
if(a[x[enode.s]][x[i]]>0)
{//可行儿子结点
float cc=enode.cc+a[x[enode.s]][x[i]];
float rcost=enode.rcost-minOut[x[enode.s]];
float b=cc+rcost;//最小费用下界
if(b<bestc)
{//子树可能含最优解,结点插入最小堆
int []xx=new int[n];
for(int j=0;j<n;j++)xx[j]=x[j];
xx[enode.s+1]=x[i];
xx[i]=x[enode.s+1];
HeapNode node=new HeapNode(b,cc,rcost,enode.s+1,xx);
heap.insert(node);
}
}
}
//取下一扩展结点
enode=(HeapNode)heap.removemin();
}
x=enode.x;//将取得的最佳路线中最后一个结点的完整路线赋给x
for(int i=0;i<n;i++)
v[i+1]=x[i];
return bestc;

}

public static void main(String[] args) {
	Scanner in=new Scanner(System.in);
	System.out.println("请输入地图的城市数:");
	n=in.nextInt();
	a=new float[n+1][n+1];
	/*
	 * 例如:
	 *  0 30 6 4
		30 0 5 10
		6 5 0 20
		4 10 20 0
	又如:
		0 5 4 6
		5 0 3 7
		4 3 0 12
		6 7 12 0
	 */
	System.out.println("请输入地图的邻接矩阵:");
	for(int i=1;i<5;i++) {
		for(int j=1;j<5;j++) {
			a[i][j]=in.nextFloat();
		}
	}
	int[] v= {0,0,0,0,0};//最优路线

System.out.println(“最优路线花费和:”+bbTSP(v));
System.out.println(“最优路线:”);
for(int i=1;i<5;i++) {
System.out.print(v[i]+" ");
}
}

}

运行结果:
在这里插入图片描述

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: TSP问题是指旅行商问题,即给定一些城市和它们之间的距离,求出一条经过每个城市一次且回到起点的最短路径。 优先队列分支限界法是一种求解TSP问题算法。它采用分支限界法的思想,将问题分解为若干个子问题,并通过优先队列来管理这些子问题。每次从队列中取出一个子问题进行求解,求解过程中通过剪枝操作来减少搜索空间,直到找到最优解。 具体来说,优先队列分支限界法的步骤如下: 1. 将起点作为当前节点,将所有未访问的城市作为子节点加入优先队列中。 2. 从队列中取出一个子节点,计算从起点到该节点的路径长度,并记录下已经访问的城市。 3. 如果已经访问了所有城市,则更新最优解,并回溯到上一个节点。 4. 如果当前路径长度已经大于最优解,则剪枝,回溯到上一个节点。 5. 如果当前路径长度小于最优解,则将该节点的所有子节点加入优先队列中。 6. 重复步骤2-5,直到队列为空。 通过优先队列分支限界法,可以在较短的时间内求解TSP问题,并得到最优解。 ### 回答2: 优先队列分支限界法是解决TSP问题的一种有效方法。随着问题规模的增大,暴力搜索算法出现了指数级别的组合数爆炸,极大地降低了算法效率。这正是我们需要寻找更加高效的算法求解TSP问题的原因所在。 优先队列分支限界法中,我们选择一组包含起始点的城市,所有其他城市未被访问。在这个基础上,以第一个节点为父亲节点,强行访问下一个节点——等价于一条边——而后又强行访问下一个未被访问的节点,直到达到出发点,并生成一条恰好经过每个节点恰好一次的回路。在这个基础上,我们就开始构建搜索树。 优先队列分支限界法时,我们会记录下每一条最小的边,然后以每个节点离根节点的距离来排序所有候选节点。我们逐个扩展并生成搜索树的分支。 以搜索树中的深度表示路径的长度,每当到达分支的时候,我们会对未被访问的节点使用评价函数评价所有子节点,并记录下评价值最小的那个节点。我们将最小的那个节点放入一个优先队列中,并重复这个步骤直到我们更新了全局最优值,或者我们已经检查了优先队列中的所有节点。 在优先队列分支限界法的过程中,我们认为所有未被访问的节点都是可行的。其次,我们选择最小的边,在每个节点中重新评价最优状态。这个方法比普通的BB算法更加节省存储空间,并且可以按照任意顺序处理节点。最后,在这个算法中,我们能够使用优先队列来进行节点扩展排序,并且在每个节点中进行子节点的评价。这个过程提高了搜索树的宽度和深度,缩短了搜索时间,能够帮助我们更快的找到最优解。 ### 回答3: 优先队列分支限界法是一种求解TSP问题的有效策略。针对旅行商问题,我们需要遍历所有可能的路径并找到最短路径。优先队列分支限界法就是根据已知的最优路径,通过剪枝和分支策略进行搜索,来寻找更优的路径。 1.剪枝过程。每次扩展新的节点时,我们可以计算当前节点的下界,如果它已经比已知的最优解要大,那么就可以剪枝,不需要再往下搜索。剪枝的目的是减少搜索空间,加快算法的运算速度。 2.分支过程。当我们找到一个新的节点时,我们需要根据其相邻节点的距离和路径长度,计算出从这个节点出发的所有可能的路径,并将它们加入到优先队列中。然后按照路径长度从小到大的顺序,依次处理队列中的每个节点,选取其中最优的一个路径进行扩展,不断重复这个过程,直到找到最优解为止。 通过优先队列分支限界法,我们可以高效地求解TSP问题,将搜索空间缩小到较小的范围,提高了算法的运算速度。但是该算法最坏情况下仍需遍历所有可能的路径,因此当问题规模较大时,仍需要适当的优化措施来提高算法的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值