算法java实现--分支限界法--旅行售货员问题

旅行售货员问题的java实现(优先队列式分支限界法)

具体问题描述以及C/C++实现参见网址

http://blog.csdn.net/liufeng_king/article/details/8952076

import java.util.Collections;
import java.util.LinkedList;

/**
 * 旅行售货员问题--优先队列式分支限界法
 * @author Lican
 *
 */
public class BBTSP {
	float[][] a;//图G的邻接矩阵
	public BBTSP(float[][] a){
		this.a=a;
	}
	public static class HeapNode implements Comparable{
		float lcost;//子树费用的下界
		float cc;//当前费用
		float rcost;//x[s:n-1]中顶点最小出边费用和
		int s;//根节点到当前节点的路径为x[0:s]
		int[] x;//需要进一步搜索的顶点是x[s+1:n-1]
		
		//构造方法
		public HeapNode(float lc,float ccc,float rc,int ss,int[] xx){
			lcost=lc;
			cc=ccc;
			s=ss;
			x=xx;
		}
		public int compareTo(Object x){
			float xlc=((HeapNode) x).lcost;
			if(lcost<xlc) return -1;
			if(lcost==xlc) return 0;
			return 1;
		}
	}
	
	public float bbTsp(int[] v){
		int n=v.length-1;//节点数
		LinkedList<HeapNode> heap=new LinkedList<HeapNode>();
		//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]<Float.MAX_VALUE&&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){
				//当前扩展结点是叶节点的父节点
				//再加两条边构成回路
				//所构成回路是否优于当前最优解
				if(a[x[n-2]][x[n-1]]!=-1&&a[x[n-1]][1]!=-1&&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.add(enode);
					Collections.sort(heap);
				}
			}else{//内部结点
				//产生当前扩展结点的儿子结点
				for(int i=enode.s+1;i<n;i++){
					if(a[x[enode.s]][x[i]]!=-1){
						//可行儿子结点
						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.add(node);
							Collections.sort(heap);
						}
					}
				}
				
			}
			
			//取下一个扩展结点
			enode=heap.poll();
		}
		//将最优解复制到v[1...n]
		for(int i=0;i<n;i++)
			v[i+1]=x[i];
		return bestc;
	}
	public static void main(String[] args) {
		//int n=4;
		//float[][] a={{0,0,0,0,0},{0,-1,30,6,4},{0,30,-1,5,10},{0,6,5,-1,20},{0,4,10,20,-1}};//a下标从1开始,0用来凑数;-1表示不同,1表示连通
		int n=5;
		float[][] a={{0,0,0,0,0,0},{0,-1,5,-1,7,9},{0,5,-1,10,3,6},{0,-1,10,-1,8,-1},{0,7,3,8,-1,4},{0,9,6,-1,4,-1}};//a下标从1开始,0用来凑数;-1表示不同,1表示连通
		BBTSP b=new BBTSP(a);
		int []v=new int[n+1];
		System.out.println("最短回路长为:"+b.bbTsp(v));
		System.out.print("最短回路为:");
		for(int i=1;i<=n;i++){
			System.out.print(v[i]+" ");
		}
	}
}
/*
==============================================================
测试数据:
int n=4;
float[][] a={{0,0,0,0,0},{0,-1,30,6,4},{0,30,-1,5,10},{0,6,5,-1,20},{0,4,10,20,-1}};

输出:
最短回路长为:25.0
最短回路为:1 3 2 4 
=======================================================================

测试数据:
int n=5;
float[][] a={{0,0,0,0,0,0},{0,-1,5,-1,7,9},{0,5,-1,10,3,6},{0,-1,10,-1,8,-1},{0,7,3,8,-1,4},{0,9,6,-1,4,-1}};

输出:
最短回路长为:36.0
最短回路为:1 5 2 3 4 
 */ 
    原文作者:分支限界法
    原文地址: https://blog.csdn.net/lican19911221/article/details/26986521
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞