近似算法-欧几里得旅行商问题JAVA语言

来源:互联网 发布:linux创建文件夹权限 编辑:程序博客网 时间:2024/05/21 22:47

1、问题描述

“旅行商问题”是指一名售货员要拜访多个地点时,如何找到从起始节拜访所有节点且仅拜访一次,最后回到起始节点的最短路径。最终形成的是一条闭合的回路,如图一所示。欧几里得旅行商问题是一种特殊的旅行商问题,它要求任意三个节点的距离满足三角形法则,即两边之和大于第三边,两边之差小于第三边。

                                                                                                 

                                                                                                                                                   图一 旅行商问题解结果

2、近似算法思想

所有的节点用相应的边连接起来构成一幅无向图,首先采用prim算法构造无向图的最小生成树,然后采用前序遍历的方法遍历无向图的最小生成树,遍历的结果就是售货员拜访所有节点的顺序。近似算法求的的拜访顺序所走过的路径不大于最短路径的2倍。prim算法的时间复杂度为O(n^2),n为节点的数量;前序遍历算法的时间复杂度为O(n),所以近似算法的时间复杂度为O(n^2),远小于动态规划法的时间复杂度O(2^n)。

3、JAVA代码

由于构造满足欧几里得旅行商问题的数据比较困难,本文假设所有节点都处于一个平面内,节点之间的距离为直线距离,因此输入参数为节点的坐标(x,y)。

3.1旅行商问题类

package approximation;

import java.util.Scanner;

public class approximation {
 private float edge[][],cost;
 private float city[][];
 private int start[],next[];
 private int TSP[],sit;
 public approximation(){
  Scanner sc=new Scanner(System.in);
  System.out.println("请输入城市的数量:");
  int num=sc.nextInt();
  city=new float[num][2];
  edge=new float[num][num];
  for(int i=0;i<num;i++){
   System.out.println("请输入第"+(i+1)+"个城市的位置:");
   city[i][0]=sc.nextFloat();
   city[i][1]=sc.nextFloat();
  }
  for(int i=0;i<num;i++){
   for(int j=0;j<num;j++){
    edge[i][j]=(float) Math.sqrt(Math.pow(city[i][0]-city[j][0], 2)+Math.pow(city[i][1]-city[j][1], 2));
   }
  }
 }
 public void approxTSP()
 {
  int n=city.length;
  float c[][]=edge;
  float[] lowcost = new float[n];
  int[] clostest = new int[n];
  boolean[] s = new boolean[n];
  start = new int[n];
  next = new int[n];

  s[0] = true; //初始化,计算未遍历城市到已遍历集合的距离
  for (int i = 1; i <n; i++) {
   lowcost[i] = c[0][i];
   clostest[i] = 0;
   s[i] = false;
  }
  for (int i = 0; i < n-1; i++) {
   float min = Float.MAX_VALUE;
   int j = 0;
   for (int k = 1; k < n; k++) { //查找距离已遍历集合最近的城市
    if ((lowcost[k] < min) && (!s[k])) {
     min = lowcost[k];
     j = k;
    }
   }
   //System.out.println(clostest[j]+",  "+j); //输出并保存
   start[i] = clostest[j];
   next[i] = j;
   s[j] = true;

   for (int k = 1; k < n; k++) { //重新计算未遍历城市到已遍历集合的距离
    if (c[j][k] < lowcost[k] && (!s[k])) {
     lowcost[k] = c[j][k];
     clostest[k] = j;
    }
   }
  }
 }
 public void PreTra(){ //前序遍历最小生成树
  int n=city.length;
  TSP=new int[n];
  sit=0;
  PreTraverse(0);
  System.out.println("旅行路径为:"); //输出并计算旅行代价
  cost=edge[TSP[n-1]][0];
  for(int i=0;i<n;i++){
   System.out.print(TSP[i]+" ");
   if(i<n-1){
    cost=cost+edge[TSP[i]][TSP[i+1]];
   }
  }
  System.out.print("\n旅行总代价为"+cost+"\n");
 }
 private void PreTraverse(int a) { //前序遍历最小生成树的递归代码
  int n=city.length;
  TSP[sit]=a;
  sit++;
  for(int i=0;i<n-1;i++){
   if(start[i]==a){
    PreTraverse(next[i]);
   }
  }
 }
}

3.2主函数使用旅行商问题类

package approximation;

public class TSP {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  approximation approx=new approximation();
  approx.approxTSP(); //生成最小生成树
  approx.PreTra(); //前序遍历
 }
}

0 0