旅行售貨員_分支限界法_java實現

旅行售貨員問題用回溯法貌似更容易實現一些,網上代碼很多。這裏給出用分支限界法的java實現。

問題描述:
某售貨員要到若干城市去推銷商品,已知各城市之間的路程(或旅費)。他要選定一條從駐地出發,經過每個城市一遍,最後回到駐地的路線,使總的路程( 或旅費)最小。各個城市之間可能是有向連通的、無向連通的、以及存在某個城市不連通的情況,你的程序應該能夠處理所有可能的情況。如下圖表示各個城市間無向連通。

輸入:

第一行爲一個整數n(n<=10),表示城市的總個數。接下來是一個n*n的矩陣,用來表示城市間的連通情況以及花費,例如path[i][j]=lenlen=-1表示從城市i到城市j沒有通路,len>0表示從ij的路程長度爲len。對於上面圖示的問題我們可以按照下面方式輸入:

4
-1 30 6 4
30 -1 5 10
6 5 -1 20
4 10 20 -1

輸出:

輸出佔一行,對於給定的問題,如果找到了最小路程(花費),輸出該最小花費,如果沒有通路可以到達每個城市,則輸出-1

輸入樣例:

4
-1 30 6 4
30 -1 5 10
6 5 -1 20
4 10 20 -1

輸出樣例:

25

//旅行售貨員問題,用分支限界法實現 2010-10-28

 

import java.util.Scanner;

public class Main
{

//Main
public static void main(String args[])
{
Scanner s=new Scanner(System.in);
int n=0;//結點的個數
String line=s.nextLine();//讀入n
n=Integer.parseInt(line);
a=new float[n][n];
int []vv=new int[n];

for(int i=0;i<n;i++)
{
line=s.nextLine();
String []sArray=line.split(" ");
for(int j=0;j<sArray.length;j++)
{
a[i][j]=Integer.parseInt(sArray[j]);
}
}
System.out.println(bbTsp(vv));
}//Main


static float [][]a;//圖的鄰接矩陣
//static float a[][]={{-1,-1,-1,2},{2,-1,-1,-1},{1,3,-1,-1},{-1,-1,1,-1}};
//static float a[][]={{-1,30,6,4},{30,-1,5,10},{6,5,-1,20},{4,10,20,-1}};
//static float a[][]={{5,5,5,5},{5,5,5,5},{5,5,5,5},{5,5,5,5}};

private static class HeapNode implements Comparable
{
float lcost,//子樹費用下界
cc,//當前費用
rcost;//X[s:n-1]中頂點最小出邊費用和
int s;//根節點到當前結點的路徑爲X[0:s]
int []x;//需要進一步搜索的結點是x[s+1:n-1]

//HeapNode的構造函數
HeapNode(float lc,float ccc,float rc,int ss,int []xx)
{
lcost=lc;
cc=ccc;
s=ss;
x=xx;
}//HeapNode 構造函數

public int compareTo(Object x)
{
float xlc=((HeapNode)x).lcost;
if(lcost<xlc)
return -1;
if(lcost==xlc)
return 0;
return 1;
}

}//class HeapNode

public static int  bbTsp(int []v)
{
int n=v.length;
MinHeap heap=new MinHeap(100);
float []minOut=new float[n];//minOut[i]是頂點i的最小出邊費用
float minSum=0;//最小出邊費用和

//計算最小出邊費用和
for(int i=0;i<n;i++)
{
float min=Float.MAX_VALUE;
for(int j=0;j<n;j++)
{
if(a[i][j]!=-1&&a[i][j]<min)
min=a[i][j];//有迴路
}//for j

if(min==Float.MAX_VALUE)
{
return -1;//無迴路
}//if

minOut[i]=min;
minSum+=min;
}//for i

//初始化
int []x=new int[n];
for(int i=0;i<n;i++)
{
x[i]=i;
}
HeapNode enode=new HeapNode(0,0,minSum,0,x);
float bestc=Float.MAX_VALUE;

//搜索排列空間樹
while(enode!=null&&enode.s<n-1)
{
//System.out.println(bestc);
x=enode.x;
if(enode.s==n-2)//葉子結點
{
if(a[x[n-2]][x[n-1]]!=-1&&
a[x[n-1]][1]!=-1||
bestc==Float.MAX_VALUE)//當前最優解還不存在的情況
{
bestc=enode.cc+a[x[n-2]][x[n-1]]+a[x[n-1]][0];
enode.cc=bestc;
enode.lcost=bestc;
enode.s++;
heap.put(enode);
}
}//if(enode.s==n-2)

//if(enode.s!=n-2)
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.put(node);
}//if(b<bestc)
}//if 可行兒子結點
}//for
}//else,if(enode.s!=n-2)

enode=(HeapNode)heap.removeMin();
}//while
for(int i=0;i<n;i++)
v[i]=x[i];
return (int)bestc;
}//Class bbTsp



//構造最小堆
public static class MinHeap
{
private HeapNode[] heapArray; // 堆容器
private int maxSize; // 堆的最大大小
private int currentSize=0; // 堆大小

//構造函數
public MinHeap(int _maxSize)
{
maxSize = _maxSize;
heapArray = new HeapNode[maxSize];
currentSize = 0;
}

//自上而下調整
public void filterDown(int start, int endOfHeap)
{
int i = start;
int j = 2 * i + 1; // j是i的左子女位置
HeapNode temp = heapArray[i];

while (j <= endOfHeap)
{ // 檢查是否到最後位置
if (j < endOfHeap // 讓j指向兩子女中的小者
&& heapArray[j].cc > heapArray[j + 1].cc)
{
j++;
}
if (temp.cc <= heapArray[j].cc)
{ // 小則不做調整
break;
} else
{ // 否則小者上移,i,j下降
heapArray[i] = heapArray[j];
i = j;
j = 2 * j + 1;
}
}
heapArray[i] = temp;
}//filterDown

//自下而上的調整:從結點start開始到0爲止,自下向上比較,如果子女的值小於雙親結點的值則互相交換
public void filterUp(int start)
{
int j = start;
int i = (j - 1) / 2;
HeapNode temp = heapArray[j];

while (j > 0)
{ // 沿雙親結點路徑向上直達根節點
if (heapArray[i].cc <= temp.cc)
{// 雙親結點值小,不調整
break;
} else {// 雙親結點值大,調整
heapArray[j] = heapArray[i];
j = i;
i = (i - 1) / 2;
}
heapArray[j] = temp; // 回送
}
}//filterUp

//插入結點
public void put(HeapNode node) 
{
HeapNode newNode = node;
heapArray[currentSize] = newNode;
filterUp(currentSize);
currentSize++;

}//put

//刪除堆中的最小值
public HeapNode removeMin() 
{
HeapNode root = heapArray[0];
heapArray[0] = heapArray[currentSize - 1];
currentSize--;
filterDown(0, currentSize - 1);
return root;
}
}//class MinHeap
}//class Main


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章