基于EasyOpt.jar的边互换启发式算法LK2opt和LK3opt求解TSP问题

 

3.1 TSP问题概述

旅行商问题(Travelling Salesman Problem,TSP)可描述为一个商人需要到n个城市推销商品,每两个城市ij之间的距离为,商人从其居所城市出发,经过每个城市一次后再返回居所城市,确定其城市行走顺序以实现所走路径总里程最短的优化问题。TSP还可以细分为对称和非对称两大类问题,当时,称为对称旅行商问题STSP,否则称非对称旅行商问题ATSP。如果旅行商问题没有其他约束,可以使用下列数学模型对其进行描述:

                                           (3-1)

                                 (3-2)

                                 (3-3)

                   (3-4)

                            (3-5)

以上是基于图论的TSP问题数学模型,其中:式(3-5)约束了决策变量是0-1变量,表示商人行走的路线包含城市i到城市j之间的路径,表示商人没有选择走这条路,约束可以减少变量的个数,使得决策变量的数量为个,而非n2个;式(3-1)为路径总里程最小的目标函数;式(3-2)约束商人从城市i只能出来一次;式(3-3)约束商人只能进入城市j一次;式(3-2)和(3-3)约束了商人经过每个城市仅一次;仅有(3-2)和(3-3)的约束无法避免回路的产生,一条回路是由个城市和k条弧组成,因此,式(3-4)约束旅行商在任何一个城市子集中不形成回路,其中|s|表示集合s中元素个数;此时,FD中满足(3-2),(3-3)和(3-4)的可行解;f为目标函数。

例3.1:假设商人需要到9个城市进行产品推销,9个城市之间的相互距离如表3.1所示,如何安排其推销路径以实现行驶路程最短?

表3.1 TSP问题示例城市之间的相对距离

城市

C1

C2

C3

C4

C5

C6

C7

C8

C9

C1

0

15

19

30

6

11

18

14

24

C2

15

0

34

44

14

23

29

4

38

C3

19

34

0

16

22

15

19

32

9

C4

30

44

16

0

35

30

18

44

7

C5

6

14

22

35

0

9

24

11

28

C6

11

23

15

30

9

0

24

20

23

C7

18

29

19

18

24

24

0

30

15

C8

14

4

32

44

11

20

30

0

37

C9

24

38

9

7

28

23

15

37

0

以城市1为起点,路径1-2-8-5-6-3-9-4-7-1可以获得路径总长度为106。

旅行商问题具有重要的实际意义和工程背景。它一开始是为交通运输而提出的,比如飞机航线安排、送邮件、快递服务、设计校车行进路线等等。实际上其应用范围扩展到了许多其他领域。印制电路板钻孔是TSP应用的经典例子,在一块电路板上打成百上千个孔,钻头在这些孔之间移动,相当于对所有的孔进行一次巡游。把这个问题转化为TSP,孔相当于城市,孔到孔之问的移动时间就是距离。此外,旅行商问题还有电缆和光缆布线、晶体结构分析、数据串聚类等多种用途。

3.2. 边互换启发式算法LK2opt和LK3opt原理介绍

3.2.1 边互换算法概述

有些算法通过随机互换当前解的两个点的位置形成新的可行解,如果新解总里程优于旧里程,则使用新解替换旧解,以逐渐逼近问题的最优解。鉴于TSP问题中点互换能够改善解的质量,那么边的互换应该也能够改善解的质量,Lin在1965年给出了边互换算法的雏形,并于1973年同Kernighan对其算法进行详细设计和算例实验,发现按照这种思路进行TSP问题优化求解的质量要好于之前的一些启发式算法,后续将该类算法使用LK缩写代替。

LK算法基于边交换来逐步改善并获得最后的近似最优解,关键点是选择边并进行替换。TSP可行解中每条边都可以用一个点对来表示,例如n=5的TSP问题的一个可行解为{1-4-3-5-2-1},这个可行解中包含的边有{1,4}、{4,3}、{3,5}、{5,2}和{2,1}。对称TSP的边数量有n(n-1)/2条边,非对称TSP的边数量有n(n-1)条边。对于n指定的TSP问题,它的边集合是确定的,但是对于其一个可行解,如何将其两条边互换、三条边互换或多条边互换,则需要考虑互换之后边对应的点集之间是否能够形成可行解。以前面n=5的解为例,如果希望将边{4,3}和{5,2}使用另外两条边互换,那么另外两条边的选择必须考虑解的可行解,即另外两条边只能从2、3、4、5这四个节点所组成的点对之中选择,而且还需要考虑原路径中没有互换的三条边与新选择的两条边之间的连通性。

3.2.2 两对边互换算法LK2opt

首先以LK算法中两条边互换来进行算法的细节分析。将问题一个可行解中的各条边按照节点连接关系可以连接成一个环状结构,要进行两条边的互换可能会出现如下图的两种情况,图(a)中使用边y1和y2替换原有的边x1和x2,新解是可行解;而图(b)的新解则是不可行解,因为将x1和x2两条边分别用y1和y2替换后,将形成两个独立的子回路,而非一个完整的回路。

(a)                                (b)

图1 Lin2-opt两边互换的两种情况

LK算法虽然出发点是边互换,但是计算机运算过程中边是使用其两个端点点对来表示的,因此在运算过程中选择互换的四条边时,需要考虑边对应的端点必须满足图(a)的情况,以便互换后的新解是可行解。

LK2opt的基本步骤是先随机生成或按照其他简单启发式算法生成一条可行解,然后依次以路径各个位置的点作为t1,据此确定换出边x1,然后寻找以t2一个端点的不在当前解中的边y1,也就确定了点t3,再以t3为一个端点找满足上图(a)中情况的t31及其换出边x2,则确定了t31和t1为两个端点边y2。由于确定了x1之后,t3可以在除了t1、t2和t12这三点之外的任何一点中选择,即t3可选对象数量有n-3个;当t1、t2和t3确定之后,t31也随之确定,没有第二种选择,因此确定x1之后,可以生成n-3个可行解,然后从这n-3个可行解中找出最好的解同原有可行解比较,如果有改善则使用新解替换原有可行解,重复次循环过程,直至t1对整个路径循环了一个周期。

LK2opt算法主要步骤如下:

Step1随机生成路径T

Step2improved=true

Step3while(improved)

Step3.1 improved=false,生成全部节点的一个随机排序S,然后对路径T通过如下步骤进行两条边的互换操作

Step3.2 令i=1

Step3.3 对S中的第i个节点t1的关联边x1进行2-opt操作,边x1可能有两个,一个是节点t1同其紧前关联节点t11之间的边,一个是节点t1同其紧后关联节点t2之间的边。令j=1时,x1为t1-t11之间的边;当=-1时,x1为t1 - t2之间的边。令j=1,执行Step3.4;

Step3.4根据ij确定x1;

Step3.5k=1

Step3.6当前边为x1,另一个节点为t2,找出以t2为一个端点,另一个端点为t1之后的第k个端点,如果该端点不是t1、t2和t12,两条边互换后得到新解T',如果f(T')<f(T),则执行Step3.7;否则执行step3.8;

Step3.7: 令T=T',improved=true;

Step3.8k=k+1,如果k<n-3,执行Step3.6;否则执行Step3.9;

Step3.9如果j=-1,执行Step3.10;否则j=-1,执行Step3.4;

Step3.10: 令i=i+1,如果in,执行Step3.3;否则执行Step4;

Step4 输出结果

3.2.3 三对边互换算法LK3opt

    两边进行互换产生新可行解的过程相对不是太复杂,而进行三边互换的过程就比较复杂。由于三对边的互换涉及到6个点,可以根据点的相对位置进行各种情况下边的选择可行性分析。下面以边x1两个端点中t2在t1顺时针或逆时针方向进行分别分析,两种情形下后续点的选择均有八种可能性,而八种可能性中只有四种可以产生可行解,因此对某一可行解进行LK3-opt算法进行优化时需要对八种产生可行解的情况进行分析和解的对比。

图2和图3分别为t2在t1顺时针时解可行性分析总结图和详解图。

图2 LK3-opt中t2在t1顺时针方向时解的可行性分析总结图

(a)                    (b)

(c)                    (d)

(e)                    (f)

(g)                    (h)

图3 LK3-opt中t2在t1顺时针方向时解可行性分析详解图

    图(a)和图(b)是t2在t1顺时针方向,t4在t3逆时针方向,t5在t4逆时针方向时,t6在t5不同方向下的两种结果。图(a)为t6在t4和t5之间,则此时x1、x2和x3三条边分别使用y1、y2和y3三条边交换后能够形成可行解;图(b)为t6在t5和t2之间,交换三条边之后将形成两个子回路,不能形成可行解。

图(c)和图(d)是t2在t1顺时针方向,t4在t3逆时针方向,t5在t3顺时针方向时,t6在t5不同方向下的两种结果。图(c)为t6在t3和t5之间,则此时x1、x2和x3三条边分别使用y1、y2和y3三条边交换后能够形成可行解;图(d)为t6在t5和t1之间,交换三条边之后将形成两个子回路,不能形成可行解。

图(e)和图(f)是t2在t1顺时针方向,t4在t3顺时针方向,t5在t3逆时针方向时,t6在t5不同方向下的两种结果。图(e)为t6在t3和t5之间,则此时x1、x2和x3三条边分别使用y1、y2和y3三条边交换后能够形成可行解;图(f)为t6在t5和t2之间,交换三条边之后仍然能够形成可行解。

图(g)和图(h)是t2在t1顺时针方向,t4在t3顺时针方向,t5在t4顺时针方向时,t6在t5不同方向下的两种结果。图(g)为t6在t4和t5之间,则此时x1、x2和x3三条边分别使用y1、y2和y3三条边交换将形成两个子回路,不能形成可行解;图(h)为t6在t5和t1之间,交换三条边之后仍然形成了两个子回路,不能形成可行解。

图4和图5分别为t2在t1逆时针时解可行性分析总结图和详解图。

图4 LK3-opt中t2在t1逆时针方向时解的可行性分析总结图

(a)                    (b)

(c)                    (d)

(e)                    (f)

(g)                    (h)

图5 LK3-opt中t2在t1逆时针方向时解可行性分析详解图

图5分别对应图4中的八种情况,分析过程类似于图3,这里不再赘述。

综上所述,LK3-opt的判定过程较为复杂,但是判定过程还是可以罗列清楚的,可以在边的互换过程中不断进行解的改善,最终获得近似最优解。

3.3 Easyopt.jar中的LK2opt和LK3opt方法

3.3.1 算法程序

TSP问题相关优化算法集成在easyopt.jar优化算法包中的TSP类中,该类中的方法及其作用如下表:

限定符和类型

方法和说明

static double

getTSPDist(double[][] dist, int[] route)

根据输入的城市之间距离矩阵和旅行商行走路线,获取该路线的总长度

static void

leftShift(int[] route, int n)

对一维数组向左偏移n个位数,不包含第一个数字

static int[]

optByEnumerate(double[][] dist)

根据输入的TSP各个节点间的距离矩阵,运用枚举法对全部可能的路径进行枚举比较,并返回输出最优里程和路径顺序,只适合于城市数量较少的问题, 否则运算时间太长

static int[]

optByLin2opt(double[][] dist)

根据输入的TSP各个节点间的距离矩阵,运用Lin和Kernighan的2-opt【2对边交换】方法进行优化,并返回输出最优里程的路径顺序

static int[]

optByLin3opt(double[][] dist)

根据输入的TSP各个节点间的距离矩阵,运用Lin和Kernighan的3-opt【3对边交换】方法进行优化,并返回输出最优里程的路径顺序

static int[]

optByNearNeighbor(double[][] dist)

根据输入的TSP各个节点间的距离矩阵,运用最近邻法求出TSP近似最优解,并返回输出近似最优里程和路径顺序,可适用于大规模的问题,但是近似最优解的质量难以得到保障

static int[]

optTSPBy2opt(double[][] dist)

根据输入的参数:各个节点之间的相互距离,获得该TSP问题距离最短的路径顺序

static int[]

optTSPBy3opt(double[][] dist)

根据输入的参数:各个节点之间的相互距离,采用3点交换的优化策略获得该TSP问题距离最短的路径顺序

static int[]

optTSPByTabu(double[][] dist, int[] paras)

根据输入的参数:各个节点之间的相互距离,使用禁忌搜索算法获得该TSP问题距离最短的路径 ----与optTSPByTabu2的区别:optTSPByTabu2每次迭代比较指定特定数量的候选解;本方法每次迭代比较全部邻域解

    该类集成在easyopt0301版之后的包中,请到www.iescm.com/easyopt中下载更新,这些方法有的在后续示例中需要使用到,有的不需要使用,但是这里都将其列出以供参考。其中optByLin2opt和optByLin3opt方法分别实现Lin和Kernighan提出的两对边互换和三对边互换寻优算法。

3.3.2 算法源代码

optByLin2opt和optByLin3opt方法可以通过easyopt.jar包直接调用,附录部分给出这两个方法的源代码,以供感兴趣的读者深入学习。

3.3.2 optByLin2opt和optByLin3opt方法使用示例

将easyopt0301.jar包导入eclipse或idea集成开发环境之后,新建一个类文件TestLKopt.class,其程序体如下,通过变换变量dist的值即可求解不同参数下的TSP问题。

TestLKopt.class源代码

import java.util.Arrays;

import easyopt.common.EasyMath;

import easyopt.instances.TSPinstances;

import easyopt.tsp.TSP;

public class TestLKopt {

  public static void main(String[] args) {

    // TODO Auto-generated method stub

      System.out.println("----------简单算例求解结果----------");

      simpleTSP();

      System.out.println("----------稍微复杂算例求解结果----------"); 

      complexTSP();

  }

 

  public static void simpleTSP(){

    double[][] distsDouble={{0,15,19,30,6,11,18,14,24},{15,0,34,44,14,23,29,4,38},

        {19,34,0,16,22,15,19,32,9},{30,44,16,0,35,30,18,44,7},{6,14,22,35,0,9,24,11,28},

        {11,23,15,30,9,0,24,20,23},{18,29,19,18,24,24,0,30,15},{14,4,32,44,11,20,30,0,37},

        {24,38,9,7,28,23,15,37,0}}; 

    int[] route1 = TSP.optByLin2opt(distsDouble);

    int[] route2 = TSP.optByLin3opt(distsDouble);

    double dist1 = TSP.getTSPDist(distsDoubleroute1);

    double dist2 = TSP.getTSPDist(distsDoubleroute2);

    System.out.println("the optimal distance by Lin2opt:   "dist1);

    System.out.println("the optimal route by Lin2opt: "+ Arrays.toString(route1));

    System.out.println("the optimal distance by Lin3opt:   "dist2);

    System.out.println("the optimal route by Lin3opt: "+ Arrays.toString(route2));     

  }

  /**稍微复杂一些的TSP问题数据示例,使用*/

  public static void complexTSP(){

    TSPinstances tspObj = new TSPinstances();//构建算例对象

    tspObj.init_eil51();//使用eil51的算例初始化tspObj对象

    double[][] xy = tspObj.getPosXY();//tspObj中的数据提取出来,主要是各个节点的xy平面坐标值

    double[][] distsDouble=EasyMath.calDist(xy, 0);//根据xy值生成点之间的距离矩阵 

    int[] route1 = TSP.optByLin2opt(distsDouble);

    int[] route2 = TSP.optByLin3opt(distsDouble);

    double dist1 = TSP.getTSPDist(distsDoubleroute1);

    double dist2 = TSP.getTSPDist(distsDoubleroute2);

    System.out.println("the optimal distance by Lin2opt:   "dist1);

    System.out.println("the optimal route by Lin2opt: "+ Arrays.toString(route1));

    System.out.println("the optimal distance by Lin3opt:   "dist2);

    System.out.println("the optimal route by Lin3opt: "+ Arrays.toString(route2));     

  }

 

}

注:complexTSP方法中第一行命令中使用的是easyopt.jar包中的TSP算例类,该类中当前集成了部分常见TSP问题测试算例数据,包括算例中节点的XY坐标值。

上述程序执行结果如下:

----------简单算例求解结果----------

the optimal distance by Lin2opt:   108.0

the optimal route by Lin2opt: [0, 6, 3, 8, 2, 5, 4, 1, 7]

the optimal distance by Lin3opt:   111.0

the optimal route by Lin3opt: [0, 4, 5, 2, 8, 3, 6, 1, 7]

----------稍微复杂算例求解结果----------

the optimal distance by Lin2opt:   468.0

the optimal route by Lin2opt: [23, 13, 24, 12, 18, 41, 39, 40, 3, 17, 46, 50, 45, 10, 31, 21, 1, 15, 49, 8, 48, 37, 4, 11, 36, 16, 43, 14, 44, 32, 38, 9, 29, 33, 20, 28, 19, 34, 35, 2, 27, 30, 25, 6, 7, 0, 26, 5, 47, 22, 42]

the optimal distance by Lin3opt:   441.0

the optimal route by Lin3opt: [39, 40, 12, 24, 13, 23, 42, 6, 22, 5, 47, 7, 25, 30, 27, 2, 19, 34, 35, 21, 0, 26, 50, 45, 31, 10, 37, 4, 48, 8, 49, 15, 1, 28, 20, 33, 29, 9, 38, 32, 44, 14, 43, 36, 16, 11, 46, 17, 3, 41, 18]

附录 Easyopt.jar中的LK2opt和LK3opt方法源代码

import java.util.Arrays;

import easyopt.common.EasyMath;

import easyopt.tsp.TSP;

public class LK2optAndLK3opt {

  /**根据输入的TSP各个节点间的距离矩阵,运用LinKernighan2-opt2条边交换】方法进行优化,

   * 并返回输出最优里程的路径顺序

   * @param dist 各个节点之间的距离矩阵,行列相同的二维数组

   * @return 路径中各个顺序的城市编号【从0开始编号】;如果dist中出现数据错误,则返回值的城市编号均为-1

   * */

  public static int[] optByLin2opt(double[][] dist){

    //算法步骤是先根据城市的数量,生成全部城市的全排列,然后对每个排列计算其路径总里程

    int row = dist.length;

    int col =dist[0].length;

    int[] route = new int[row];

    //判断距离矩阵行列长度是否相同   

    if(row!= col){

      for(int i=0;i<row;i++){

        route[i]=-1;

      }

      System.out.println("TSP问题中城市距离矩阵dist的行列长度不相等");

      return route;

    }

    if(row<9){//如果节点数量少于9个,则直接使用枚举法获得最优解

      route = TSP.optByEnumerate(dist);

      return route;

    }

    //以最后一个城市为始终点,来减少排列数量

    int cityQty = row;

    //step1 :随机生成一个路径

    route = EasyMath.randPerm(cityQty);

    route=TSP.optByNearNeighbor(dist);

   // System.out.println("init route:  "+Arrays.toString(route));

    double bestFit = TSP.getTSPDist(distroute);

    int[] bestRoute = Arrays.copyOf(routecityQty);

    boolean improved = true;

    int[][] routeEdges =  new int[cityQty][cityQty];//record whether the edges include in the present route

    routeEdges = getTheEdgeValue(route);

    int nowLoop=0;

    //step2: 循环迭代进行两条边的互换和更新

    while(improved||nowLoop<20){

      if(!improved){

        route = Arrays.copyOf(bestRoutecityQty);

      }

      improved = false;

      int[] randCities = EasyMath.randPerm(cityQty);//随机各个城市节点的乱序,从0开始,控制每次以哪个城市为其实节点t1【第一条边的一个顶点】

      for(int i=0;i<cityQty;i++){

        int t1node = route[randCities[i]];//相当于算法中的节点t1

        for(int j=-1;j<2;j=j+2){//当前节点左联边或右联边作为交换的x1

          int[] cityPositions =getCityPositionFromRoute(route);//各个城市在当前路径中的索引位置,从0开始编号

          routeEdges = getTheEdgeValue(route);

          int t1pos = cityPositions[t1node];// [0,n-1]

          int t2pos = t1pos +j;//the t2pos may be less than 0 while the t1pos equals 0;

                               //the t2pos may be bigger than cityQty-1 while the t1pos equals cityQty-1

                               //[-1,n]

          int t2node = route[Math.floorMod(t2poscityQty)];

          //now the two nodes of the broken edge are determined,

          //  then we should find the t3 and the link edge y1

          double x1Dist = dist[t1node][t2node];

          int[] randCity2 = EasyMath.randPerm(cityQty);

          for(int k=0;k<cityQty;k++){

            int t3node = randCity2[k];

            if(routeEdges[t2node][t3node]==0&&t2node!=t3node){//edge: t2node-k is not in the present route

              double y1Dist = dist[t2node][t3node];

              if(x1Dist>y1Dist){//condition 1

                int t3pos =  cityPositions[t3node];//[0,n-1]

                int preT3pos =  t3pos-1;

                int nextT3pos =  t3pos+1;

                //now we have t1pos,t2pos,t3pos,preT3pos,nextT3pos, then we need judge and decide the t4node

                // all of them are in [-1,cityQty], how to decide the right t4

                int t4pos;//[-1,n]

                if(t2pos<t1pos){

                  t4pos = nextT3pos;

                }else{

                  t4pos = preT3pos;

                }

                //t4pos is not equal to t1pos, or t2pos

                double y2dist = dist[route[Math.floorMod(t4poscityQty)]][route[t1pos]];

                double x2dist =dist[t2node][t3node];

                if(Math.floorMod(t4poscityQty)!=Math.floorMod(t1poscityQty)

                    &&Math.floorMod(t4poscityQty)!=Math.floorMod(t2poscityQty)

                    &&y2dist<x2dist){

                  //System.out.println(k+ "  t1  t2  t3  t4: "+ t1pos+"  "+ t2pos+"  "+ t3pos+"  "+ t4pos+"  ");                 

                  //get the right t4 node, so change the route

                  if(t2pos<t1pos){//in reversing process, t2pos clockwise to t4pos

                    int midPos = t2pos;

                    if(t2pos<t4posmidPos+=cityQty;

                    int gapNum = midPos-t4pos+1;// the quantity of the reverse nodes

                    int pairQty = (int) Math.floor(gapNum/2);

                   

                    for(int p=0;p<pairQty;p++){

                      int t2_t4Idx = Math.floorMod(t2pos-pcityQty);

                      int t4_t2Idx = Math.floorMod(t4pos+pcityQty);

                      int midVal = route[t2_t4Idx];

                      route[t2_t4Idx]=route[t4_t2Idx];

                      route[t4_t2Idx]=midVal;

                    }

                    //System.out.println(Arrays.toString(route)+" pairQty: "+pairQty);

                  }else{//in reversing process, t2pos anti-clockwise to t4pos

                    int midPos = t4pos;

                    if(t4pos<t2posmidPos+=cityQty;

                    int gapNum = midPos-t2pos+1;// the quantity of the reverse nodes

                    int pairQty = (int) Math.floor(gapNum/2);

                    for(int p=0;p<pairQty;p++){

                      int t2_t4Idx = Math.floorMod(t2pos+pcityQty);

                      int t4_t2Idx = Math.floorMod(t4pos-pcityQty);

                      int midVal = route[t2_t4Idx];

                      route[t2_t4Idx]=route[t4_t2Idx];

                      route[t4_t2Idx]=midVal;

                    }                   

                  }

                  double nowFit = TSP.getTSPDist(distroute);

                  if(nowFit<bestFit){

                    bestFit = nowFit;

                    bestRoute = Arrays.copyOf(routecityQty);

                    nowLoop--;

                  }

                  improved = true;

                  break;

                }

              }

            }

          }

         

        }

      }

      //System.out.println(getTSPDist(dist, route));

      nowLoop++;

    }

    return bestRoute;

  }

  /**根据输入的TSP各个节点间的距离矩阵,运用LinKernighan3-opt3条边交换】方法进行优化,

   * 并返回输出最优里程的路径顺序

   * @param dist 各个节点之间的距离矩阵,行列相同的二维数组

   * @return 路径中各个顺序的城市编号【从0开始编号】;如果dist中出现数据错误,则返回值的城市编号均为-1

   * */

  public static int[] optByLin3opt(double[][] dist){

    //算法步骤是先根据城市的数量,生成全部城市的全排列,然后对每个排列计算其路径总里程

    int row = dist.length;

    int col =dist[0].length;

    int[] route = new int[row];

    //判断距离矩阵行列长度是否相同   

    if(row!= col){

      for(int i=0;i<row;i++){

        route[i]=-1;

      }

      System.out.println("TSP问题中城市距离矩阵dist的行列长度不相等");

      return route;

    }

    if(row<8){//如果节点数量少于8个,则直接使用枚举法获得最优解

      route = TSP.optByEnumerate(dist);

      return route;

    }

    int cityQty = row;

    //step1 :随机生成一个路径

    route = EasyMath.randPerm(cityQty);

    route=TSP.optByNearNeighbor(dist);

    double bestFit = TSP.getTSPDist(distroute);

    int[] bestRoute = Arrays.copyOf(routecityQty);

    boolean improved = true;

    int nowLoop=0;

    //step2: 循环迭代进行两条边的互换和更新

    while(improved||nowLoop<10){

      improved = false;     

      int[] randCities = EasyMath.randPerm(cityQty);//随机各个城市节点的乱序,从0开始,控制每次以哪个城市为其实节点t1【第一条边的一个顶点】

      for(int i=0;i<cityQty;i++){//t1 for loop

        int[] randCities2 = EasyMath.randPerm(cityQty);

        int t1pos = randCities[i];

        int t2pos,t2posGood;//t2pos is in range of [-1,n], t2pos is in range of [0,n-1]

        // ****************  t2pos is after t1pos  *******************

        t2pos = t1pos+1;

        t2posGood = Math.floorMod(t2poscityQty);

        int t1nodeIdx = route[t1pos];

        int t2nodeIdx = route[t2posGood];

        double x1dist = dist[t1nodeIdx][t2nodeIdx];// the length of edge X1     

        for(int j=0;j<cityQty;j++){//t3-t4 for loop

          boolean t5t6Break = false;//when t5t6 get an improved result, break the t3t4 for loop             

          int t3pos = randCities2[j];

          int t4post4posGood;

          //--------------t4pos is after t3pos

          t4pos=t3pos+1;

          t4posGood = Math.floorMod(t4poscityQty);

          int t3nodeIdx = route[t3pos];

          int t4nodeIdx = route[t4posGood];         

          double x2dist = dist[t3nodeIdx][t4nodeIdx];         

          double y1dist = dist[t3nodeIdx][t2nodeIdx];

          int t2posNext = t2pos+1;

          int t2posNextGood = Math.floorMod(t2posNextcityQty);

          if(x1dist>y1dist&&t1pos!=t3pos&&t1pos!=t4posGood&&t2posGood!=t3pos

              &&t2posNextGood!=t3pos){//include the condition: t2posGood!=t4posGood

          //t5pos must be between t3pos and t2pos, otherwise the new route is not feasible

            int gap_t2pos_t3pos = t3pos -t2posGood -1;// the remain points between t3pos and t2pos

            if(t3pos<t2posGood){

              gap_t2pos_t3pos = cityQty - (t2posGood - t3pos +1);

            }

            if(gap_t2pos_t3pos==2){//only two points between t2pos and t3pos, this branch is included by >2 branch

              int t5pos,t6pos,t5posGood,t6posGood;

              //case 1, t6pos is after t5pos

              t5pos = t2posGood +1;

              t6pos = t5pos +1;

              t5posGood = Math.floorMod(t5poscityQty);

              t6posGood = Math.floorMod(t6poscityQty);

              int t5nodeIdx = route[t5posGood];

              int t6nodeIdx = route[t6posGood];               

              double y2dist = dist[t4nodeIdx][t5nodeIdx];

              double x3dist = dist[t5nodeIdx][t6nodeIdx];

              double y3dist = dist[t6nodeIdx][t1nodeIdx];

              if(x1dist +x2dist +x3dist>y1dist+y2dist+y3dist){//can exchange the three pair edges

                //t1...t6..t3..t2..t5..t4..t1

                int[] newRoute = new int[cityQty];

                int nodes_t3_t6 = t3pos - t6posGood +1;// the nodes in the segment of t3-t6

                if(t3pos<t6posGood){

                  nodes_t3_t6 = cityQty -(t6posGood - t3pos - 1);

                }

                int newIdx =0;

                for(int k=0;k<nodes_t3_t6;k++){

                  newRoute[newIdx] = route[Math.floorMod(t6posGood + k,cityQty)];

                  newIdx++;

                }

                int nodes_t4_t1 = t1pos - t4posGood +1;// the nodes in the segment of t1-t4

                if(t1pos<t4posGood){

                  nodes_t4_t1 = cityQty -(t4posGood - t1pos - 1);

                }

                for(int k=0;k<nodes_t4_t1;k++){

                  newRoute[newIdx] = route[Math.floorMod(t4posGood + k,cityQty)];

                  newIdx++;

                }

                int nodes_t2_t5 = t5pos - t2posGood +1;// the nodes in the segment of t5-t2

                if(t5pos<t2posGood){

                  nodes_t2_t5 = cityQty -(t2posGood - t5pos - 1);

                }

                for(int k=0;k<nodes_t2_t5;k++){

                  newRoute[newIdx] = route[Math.floorMod(t2posGood + k,cityQty)];

                  newIdx++;

                }               

                route = Arrays.copyOf(newRoutecityQty);

                improved = true;               

                break;

              }

              //case 2, t6pos is before t5pos

              t5pos = t2posGood +1;

              t6pos = t5pos - 1;

              t5posGood = Math.floorMod(t5poscityQty);

              t6posGood = Math.floorMod(t6poscityQty);

              t5nodeIdx = route[t5posGood];

              t6nodeIdx = route[t6posGood];               

              y2dist = dist[t4nodeIdx][t5nodeIdx];

              x3dist = dist[t5nodeIdx][t6nodeIdx];

              y3dist = dist[t6nodeIdx][t1nodeIdx];

              if(x1dist +x2dist +x3dist>y1dist+y2dist+y3dist){//can exchange the three pair edges

                //t1...t6..t2..t3..t5..t4..t1

                int[] newRoute = new int[cityQty];

                int nodes_t2_t6 = t6posGood -t2posGood +1;// the nodes in the segment of t2-t6

                if(t6posGood<t2posGood){

                  nodes_t2_t6 = cityQty -(t2posGood - t6posGood - 1);

                }

                int newIdx =0;

                for(int k=0;k<nodes_t2_t6;k++){

                  newRoute[newIdx] = route[Math.floorMod(t6posGood - k,cityQty)];

                  newIdx++;

                }

                int nodes_t5_t3 = t3pos - t5posGood +1;// the nodes in the segment of t5-t3

                if(t3pos<t5posGood){

                  nodes_t5_t3 = cityQty -(t5posGood - t3pos - 1);

                }

                for(int k=0;k<nodes_t5_t3;k++){

                  newRoute[newIdx] = route[Math.floorMod(t3pos - k,cityQty)];

                  newIdx++;

                }

                int nodes_t4_t1 = t1pos - t4posGood +1;// the nodes in the segment of t4-t1

                if(t1pos<t4posGood){

                  nodes_t4_t1 = cityQty -(t4posGood - t1pos - 1);

                }

                for(int k=0;k<nodes_t4_t1;k++){

                  newRoute[newIdx] = route[Math.floorMod(t4posGood + k,cityQty)];

                  newIdx++;

                }    

                route = Arrays.copyOf(newRoutecityQty);

                improved = true;

                break;

              }             

            }else if(gap_t2pos_t3pos>2){

              for(int h=0;h<gap_t2pos_t3pos;h++){

                int t5pos,t6pos,t5posGood,t6posGood;

                //case 1, t6pos is after t5pos

                t5pos = t2posGood +1+h;

                t6pos = t5pos +1;

                t5posGood = Math.floorMod(t5poscityQty);

                t6posGood = Math.floorMod(t6poscityQty);

                int t5nodeIdx = route[t5posGood];

                int t6nodeIdx = route[t6posGood];               

                double y2dist = dist[t4nodeIdx][t5nodeIdx];

                double x3dist = dist[t5nodeIdx][t6nodeIdx];

                double y3dist = dist[t6nodeIdx][t1nodeIdx];

                if(x1dist +x2dist +x3dist>y1dist+y2dist+y3dist&&t6posGood!=t3pos){//can exchange the three pair edges

                  //t1...t6..t3..t2..t5..t4..t1

                  int[] newRoute = new int[cityQty];

                  int nodes_t3_t6 = t3pos - t6posGood +1;// the nodes in the segment of t3-t6

                  if(t3pos<t6posGood){

                    nodes_t3_t6 = cityQty -(t6posGood - t3pos - 1);

                  }

                  int newIdx =0;

                  for(int k=0;k<nodes_t3_t6;k++){

                    newRoute[newIdx] = route[Math.floorMod(t6posGood + k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t4_t1 = t1pos - t4posGood +1;// the nodes in the segment of t1-t4

                  if(t1pos<t4posGood){

                    nodes_t4_t1 = cityQty -(t4posGood - t1pos - 1);

                  }

                  for(int k=0;k<nodes_t4_t1;k++){

                    newRoute[newIdx] = route[Math.floorMod(t4posGood + k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t2_t5 = t5pos - t2posGood +1;// the nodes in the segment of t5-t2

                  if(t5pos<t2posGood){

                    nodes_t2_t5 = cityQty -(t2posGood - t5pos - 1);

                  }

                  for(int k=0;k<nodes_t2_t5;k++){

                    newRoute[newIdx] = route[Math.floorMod(t2posGood + k,cityQty)];

                    newIdx++;

                  }

                  route = Arrays.copyOf(newRoutecityQty);

                  t5t6Break = true;

                  improved = true

                  break;

                }

                //case 2, t6pos is before t5pos

                t5pos = t2posGood +1+h;

                t6pos = t5pos - 1;

                t5posGood = Math.floorMod(t5poscityQty);

                t6posGood = Math.floorMod(t6poscityQty);

                t5nodeIdx = route[t5posGood];

                t6nodeIdx = route[t6posGood];               

                y2dist = dist[t4nodeIdx][t5nodeIdx];

                x3dist = dist[t5nodeIdx][t6nodeIdx];

                y3dist = dist[t6nodeIdx][t1nodeIdx];

                if(x1dist +x2dist +x3dist>y1dist+y2dist+y3dist&&t6posGood!=t2posGood){//can exchange the three pair edges

                  //t1...t6..t2..t3..t5..t4..t1

                  int[] newRoute = new int[cityQty];

                  int nodes_t2_t6 = t6posGood -t2posGood +1;// the nodes in the segment of t2-t6

                  if(t6posGood<t2posGood){

                    nodes_t2_t6 = cityQty -(t2posGood - t6posGood - 1);

                  }

                  int newIdx =0;

                  for(int k=0;k<nodes_t2_t6;k++){

                    newRoute[newIdx] = route[Math.floorMod(t6posGood - k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t5_t3 = t3pos - t5posGood +1;// the nodes in the segment of t5-t3

                  if(t3pos<t5posGood){

                    nodes_t5_t3 = cityQty -(t5posGood - t3pos - 1);

                  }

                  for(int k=0;k<nodes_t5_t3;k++){

                    newRoute[newIdx] = route[Math.floorMod(t3pos - k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t4_t1 = t1pos - t4posGood +1;// the nodes in the segment of t4-t1

                  if(t1pos<t4posGood){

                    nodes_t4_t1 = cityQty -(t4posGood - t1pos - 1);

                  }

                  for(int k=0;k<nodes_t4_t1;k++){

                    newRoute[newIdx] = route[Math.floorMod(t4posGood + k,cityQty)];

                    newIdx++;

                  }                

                  route = Arrays.copyOf(newRoutecityQty);

                  t5t6Break = true;

                  improved = true

                  break;

                }                

              }

            }

           

          }

          if(t5t6Breakbreak;// break the t3t4 for loop           

         

          //----------------------t4pos is before t3pos

          t4pos=t3pos-1;

          t4posGood = Math.floorMod(t4poscityQty);

          t3nodeIdx = route[t3pos];

          t4nodeIdx = route[t4posGood];         

          x2dist = dist[t3nodeIdx][t4nodeIdx];         

          y1dist = dist[t3nodeIdx][t2nodeIdx];

          if(x1dist>y1dist&&t1pos!=t3pos&&t1pos!=t4posGood&&t2posGood!=t3pos

              &&t2posGood!=t4posGood){

          //case 1 : t5pos is between t3pos and t1pos, and t6pos is between t5pos and t3pos

            int gap_t1pos_t3pos = t1pos -t3pos -1;// the remain points between t3pos and t1pos

            if(t1pos<t3pos){

              gap_t1pos_t3pos = cityQty - (t3pos - t1pos +1);

            }

            if(gap_t1pos_t3pos>=2){

              for(int h=0;h<gap_t1pos_t3pos;h++){

                int t5pos,t6pos,t5posGood,t6posGood;

                //t6pos must be before t5pos

                t5pos = t3pos + 1 + h;

                t6pos = t5pos - 1;

                t5posGood = Math.floorMod(t5poscityQty);

                t6posGood = Math.floorMod(t6poscityQty);

                int t5nodeIdx = route[t5posGood];

                int t6nodeIdx = route[t6posGood];               

                double y2dist = dist[t4nodeIdx][t5nodeIdx];

                double x3dist = dist[t5nodeIdx][t6nodeIdx];

                double y3dist = dist[t6nodeIdx][t1nodeIdx];

                if(x1dist +x2dist +x3dist>y1dist+y2dist+y3dist&&t6posGood!=t3pos){//can exchange the three pair edges

                  //t1...t6..t3..t2..t4..t5..t1

                  int[] newRoute = new int[cityQty];

                  int nodes_t3_t6 = t6posGood -t3pos +1;// the nodes in the segment of t3-t6

                  if(t6posGood<t3pos){

                    nodes_t3_t6 = cityQty -(t3pos - t6posGood - 1);

                  }

                  int newIdx =0;

                  for(int k=0;k<nodes_t3_t6;k++){

                    newRoute[newIdx] = route[Math.floorMod(t6posGood - k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t2_t4 = t4posGood - t2posGood +1;// the nodes in the segment of t2-t4

                  if(t4posGood<t2posGood){

                    nodes_t2_t4 = cityQty -(t2posGood - t4posGood - 1);

                  }

                  for(int k=0;k<nodes_t2_t4;k++){

                    newRoute[newIdx] = route[Math.floorMod(t2posGood + k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t5_t1 = t1pos - t5posGood +1;// the nodes in the segment of t5-t1

                  if(t1pos<t5posGood){

                    nodes_t5_t1 = cityQty -(t5posGood - t1pos - 1);

                  }

                  for(int k=0;k<nodes_t5_t1;k++){

                    newRoute[newIdx] = route[Math.floorMod(t5posGood + k,cityQty)];

                    newIdx++;

                  }                 

                  route = Arrays.copyOf(newRoutecityQty);

                  t5t6Break = true;

                  improved = true;

                  break;

                }                

              }

             

             

            }

            if(t5t6Break){break;};

            //case 2 : t5pos is between t4pos and t2pos, and t6pos is between t5pos and t4pos

            int gap_t2pos_t4pos = t4posGood -t2posGood -1;// the remain points between t2pos and t4pos

            if(t4posGood<t2posGood){

              gap_t2pos_t4pos = cityQty - (t2posGood - t4posGood +1);

            }

            if(gap_t2pos_t4pos>=2){

              for(int h=0;h<gap_t2pos_t4pos;h++){

                int t5pos,t6pos,t5posGood,t6posGood;

                //t6pos must be after t5pos

                t5pos = t2pos + 1 + h;

                t6pos = t5pos + 1;

                t5posGood = Math.floorMod(t5poscityQty);

                t6posGood = Math.floorMod(t6poscityQty);

                int t5nodeIdx = route[t5posGood];

                int t6nodeIdx = route[t6posGood];               

                double y2dist = dist[t4nodeIdx][t5nodeIdx];

                double x3dist = dist[t5nodeIdx][t6nodeIdx];

                double y3dist = dist[t6nodeIdx][t1nodeIdx];

                if(x1dist +x2dist +x3dist>y1dist+y2dist+y3dist&&t6posGood!=t4posGood){//can exchange the three pair edges

                  //t1...t6..t4..t5..t2..t3..t1

                  int[] newRoute = new int[cityQty];

                  int nodes_t4_t6 = t4posGood -t6posGood +1;// the nodes in the segment of t4-t6

                  if(t4posGood<t6posGood){

                    nodes_t4_t6 = cityQty -(t6posGood - t4posGood - 1);

                  }

                  int newIdx =0;

                  for(int k=0;k<nodes_t4_t6;k++){

                    newRoute[newIdx] = route[Math.floorMod(t6posGood + k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t2_t5 = t5posGood - t2posGood +1;// the nodes in the segment of t2-t5

                  if(t5posGood<t2posGood){

                    nodes_t2_t5 = cityQty -(t2posGood - t5posGood - 1);

                  }

                  for(int k=0;k<nodes_t2_t5;k++){

                    newRoute[newIdx] = route[Math.floorMod(t5posGood - k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t3_t1 = t1pos - t3pos +1;// the nodes in the segment of t3-t1

                  if(t1pos<t3pos){

                    nodes_t3_t1 = cityQty -(t3pos - t1pos - 1);

                  }

                  for(int k=0;k<nodes_t3_t1;k++){

                    newRoute[newIdx] = route[Math.floorMod(t3pos + k,cityQty)];

                    newIdx++;

                  }                 

                  route = Arrays.copyOf(newRoutecityQty);

                  t5t6Break = true;

                  improved = true;                 

                  break;

                }                

              }

             

             

            }

           

          }        

          if(t5t6Breakbreak//break the t3t4 for loop

        }

       

        //*********t2pos is before t1pos

        t2pos = t1pos-1;

        t2posGood = Math.floorMod(t2poscityQty);

        t1nodeIdx = route[t1pos];

        t2nodeIdx = route[t2posGood];

        x1dist = dist[t1nodeIdx][t2nodeIdx];// the length of edge X1     

        for(int j=0;j<cityQty;j++){//t3-t4 for loop

          boolean t5t6Break = false;//when t5t6 get an improved result, break the t3t4 for loop             

          int t3pos = randCities2[j];

          int t4post4posGood;

          //--------------t4pos is before t3pos

          t4pos=t3pos - 1;

          t4posGood = Math.floorMod(t4poscityQty);

          int t3nodeIdx = route[t3pos];

          int t4nodeIdx = route[t4posGood];         

          double x2dist = dist[t3nodeIdx][t4nodeIdx];         

          double y1dist = dist[t3nodeIdx][t2nodeIdx];

          int t2posPre = t2pos+1;

          int t2posPreGood = Math.floorMod(t2posPrecityQty);

          if(x1dist>y1dist&&t1pos!=t3pos&&t1pos!=t4posGood&&t2posGood!=t3pos

              &&t2posPreGood!=t3pos){//include the condition: t2posGood!=t4posGood

          //t5pos must be between t3pos and t2pos, otherwise the new route is not feasible

            int gap_t2pos_t3pos = t2posGood -t3pos -1;// the remain points between t3pos and t2pos

            if(t3pos>t2posGood){

              gap_t2pos_t3pos = cityQty - (t3pos-t2posGood  +1);

            }

            if(gap_t2pos_t3pos>=2){

              for(int h=0;h<gap_t2pos_t3pos;h++){

                int t5pos,t6pos,t5posGood,t6posGood;

                //case 1, t6pos is after t5pos

                t5pos = t3pos +1+h;

                t6pos = t5pos +1;

                t5posGood = Math.floorMod(t5poscityQty);

                t6posGood = Math.floorMod(t6poscityQty);

                int t5nodeIdx = route[t5posGood];

                int t6nodeIdx = route[t6posGood];               

                double y2dist = dist[t4nodeIdx][t5nodeIdx];

                double x3dist = dist[t5nodeIdx][t6nodeIdx];

                double y3dist = dist[t6nodeIdx][t1nodeIdx];

                if(x1dist +x2dist +x3dist>y1dist+y2dist+y3dist&&t6posGood!=t2posGood){//can exchange the three pair edges

                  //t1...t6..t2..t3..t5..t4..t1

                  int[] newRoute = new int[cityQty];

                  int nodes_t2_t6 = t2posGood - t6posGood +1;// the nodes in the segment of t2-t6

                  if(t2posGood<t6posGood){

                    nodes_t2_t6 = cityQty -(t6posGood - t2posGood - 1);

                  }

                  int newIdx =0;

                  for(int k=0;k<nodes_t2_t6;k++){

                    newRoute[newIdx] = route[Math.floorMod(t6posGood + k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t3_t5 = t5posGood - t3pos +1;// the nodes in the segment of t3-t5

                  if(t5posGood<t3pos){

                    nodes_t3_t5 = cityQty -(t3pos - t5posGood - 1);

                  }

                  for(int k=0;k<nodes_t3_t5;k++){

                    newRoute[newIdx] = route[Math.floorMod(t3pos + k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t4_t1 = t4posGood - t1pos +1;// the nodes in the segment of t4-t1

                  if(t4posGood<t1pos){

                    nodes_t4_t1 = cityQty -(t1pos - t4posGood - 1);

                  }

                  for(int k=0;k<nodes_t4_t1;k++){

                    newRoute[newIdx] = route[Math.floorMod(t4posGood - k,cityQty)];

                    newIdx++;

                  }

                  route = Arrays.copyOf(newRoutecityQty);

                  t5t6Break = true;

                  improved = true

                  break;

                }

               

                //case 2, t6pos is before t5pos

                t6pos = t5pos - 1;

                t5posGood = Math.floorMod(t5poscityQty);

                t6posGood = Math.floorMod(t6poscityQty);

                t5nodeIdx = route[t5posGood];

                t6nodeIdx = route[t6posGood];               

                y2dist = dist[t4nodeIdx][t5nodeIdx];

                x3dist = dist[t5nodeIdx][t6nodeIdx];

                y3dist = dist[t6nodeIdx][t1nodeIdx];

                if(x1dist +x2dist +x3dist>y1dist+y2dist+y3dist&&t6posGood!=t3pos){//can exchange the three pair edges

                  //t1...t6..t3..t2..t5..t4..t1

                  int[] newRoute = new int[cityQty];

                  int nodes_t3_t6 = t6posGood -t3pos +1;// the nodes in the segment of t3-t6

                  if(t6posGood<t3pos){

                    nodes_t3_t6 = cityQty -(t3pos - t6posGood - 1);

                  }

                  int newIdx =0;

                  for(int k=0;k<nodes_t3_t6;k++){

                    newRoute[newIdx] = route[Math.floorMod(t6posGood - k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t5_t2 = t2posGood - t5posGood +1;// the nodes in the segment of t5-t2

                  if(t2posGood<t5posGood){

                    nodes_t5_t2 = cityQty -(t5posGood - t2posGood - 1);

                  }

                  for(int k=0;k<nodes_t5_t2;k++){

                    newRoute[newIdx] = route[Math.floorMod(t2posGood - k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t4_t1 = t4posGood - t1pos +1;// the nodes in the segment of t4-t1

                  if(t1pos>t4posGood){

                    nodes_t4_t1 = cityQty -(t1pos - t4posGood - 1);

                  }

                  for(int k=0;k<nodes_t4_t1;k++){

                    newRoute[newIdx] = route[Math.floorMod(t4posGood - k,cityQty)];

                    newIdx++;

                  }                

                  route = Arrays.copyOf(newRoutecityQty);

                  t5t6Break = true;

                  improved = true

                  break;

                }                

              }

             

            }

           

          }

          if(t5t6Breakbreak;// break the t3t4 for loop           

         

          //----------------------t4pos is after t3pos

          t4pos=t3pos+1;

          t4posGood = Math.floorMod(t4poscityQty);

          t3nodeIdx = route[t3pos];

          t4nodeIdx = route[t4posGood];         

          x2dist = dist[t3nodeIdx][t4nodeIdx];         

          y1dist = dist[t3nodeIdx][t2nodeIdx];

          if(x1dist>y1dist&&t1pos!=t3pos&&t1pos!=t4posGood&&t2posGood!=t3pos

              &&t2posGood!=t4posGood){

          //case 1 : t5pos is between t3pos and t1pos, and t6pos is between t5pos and t3pos

            int gap_t1pos_t3pos = t3pos -t1pos -1;// the remain points between t3pos and t1pos

            if(t1pos>t3pos){

              gap_t1pos_t3pos = cityQty - (t1pos - t3pos +1);

            }

            if(gap_t1pos_t3pos>=2){

              for(int h=0;h<gap_t1pos_t3pos;h++){

                int t5pos,t6pos,t5posGood,t6posGood;

                //t6pos must be before t5pos

                t5pos = t1pos + 1 + h;

                t6pos = t5pos + 1;

                t5posGood = Math.floorMod(t5poscityQty);

                t6posGood = Math.floorMod(t6poscityQty);

                int t5nodeIdx = route[t5posGood];

                int t6nodeIdx = route[t6posGood];               

                double y2dist = dist[t4nodeIdx][t5nodeIdx];

                double x3dist = dist[t5nodeIdx][t6nodeIdx];

                double y3dist = dist[t6nodeIdx][t1nodeIdx];

                if(x1dist +x2dist +x3dist>y1dist+y2dist+y3dist&&t6posGood!=t3pos){//can exchange the three pair edges

                  //t1...t6..t3..t2..t4..t5..t1

                  int[] newRoute = new int[cityQty];

                  int nodes_t3_t6 = t3pos - t6posGood +1;// the nodes in the segment of t3-t6

                  if(t6posGood>t3pos){

                    nodes_t3_t6 = cityQty -(t6posGood - t3pos - 1);

                  }

                  int newIdx =0;

                  for(int k=0;k<nodes_t3_t6;k++){

                    newRoute[newIdx] = route[Math.floorMod(t6posGood + k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t2_t4 = t2posGood - t4posGood +1;// the nodes in the segment of t2-t4

                  if(t2posGood<t4posGood){

                    nodes_t2_t4 = cityQty -(t4posGood - t2posGood - 1);

                  }

                  for(int k=0;k<nodes_t2_t4;k++){

                    newRoute[newIdx] = route[Math.floorMod(t2posGood - k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t5_t1 = t5posGood - t1pos +1;// the nodes in the segment of t5-t1

                  if(t1pos>t5posGood){

                    nodes_t5_t1 = cityQty -(t1pos - t5posGood - 1);

                  }

                  for(int k=0;k<nodes_t5_t1;k++){

                    newRoute[newIdx] = route[Math.floorMod(t5posGood - k,cityQty)];

                    newIdx++;

                  }                 

                  route = Arrays.copyOf(newRoutecityQty);

                  t5t6Break = true;

                  improved = true;

                  break;

                }                

              }

             

             

            }

            if(t5t6Break){break;};

            //case 2 : t5pos is between t4pos and t2pos, and t6pos is between t5pos and t4pos

            int gap_t2pos_t4pos = t2posGood - t4posGood -1;// the remain points between t2pos and t4pos

            if(t2posGood < t4posGood){

              gap_t2pos_t4pos = cityQty - (t4posGood - t2posGood +1);

            }

            if(gap_t2pos_t4pos>=2){

              for(int h=0;h<gap_t2pos_t4pos;h++){

                int t5pos,t6pos,t5posGood,t6posGood;

                //t6pos must be after t5pos

                t5pos = t4posGood + 1 + h;

                t6pos = t5pos - 1;

                t5posGood = Math.floorMod(t5poscityQty);

                t6posGood = Math.floorMod(t6poscityQty);

                int t5nodeIdx = route[t5posGood];

                int t6nodeIdx = route[t6posGood];               

                double y2dist = dist[t4nodeIdx][t5nodeIdx];

                double x3dist = dist[t5nodeIdx][t6nodeIdx];

                double y3dist = dist[t6nodeIdx][t1nodeIdx];

                if(x1dist +x2dist +x3dist>y1dist+y2dist+y3dist&&t6posGood!=t4posGood){//can exchange the three pair edges

                  //t1...t6..t4..t5..t2..t3..t1

                  int[] newRoute = new int[cityQty];

                  int nodes_t4_t6 = t6posGood -t4posGood +1;// the nodes in the segment of t4-t6

                  if(t6posGood<t4posGood){

                    nodes_t4_t6 = cityQty -(t4posGood - t6posGood - 1);

                  }

                  int newIdx =0;

                  for(int k=0;k<nodes_t4_t6;k++){

                    newRoute[newIdx] = route[Math.floorMod(t6posGood - k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t2_t5 = t2posGood - t5posGood +1;// the nodes in the segment of t2-t5

                  if(t2posGood<t5posGood){

                    nodes_t2_t5 = cityQty -(t5posGood - t2posGood - 1);

                  }

                  for(int k=0;k<nodes_t2_t5;k++){

                    newRoute[newIdx] = route[Math.floorMod(t5posGood + k,cityQty)];

                    newIdx++;

                  }

                  int nodes_t3_t1 = t3pos - t1pos +1;// the nodes in the segment of t3-t1

                  if(t1pos>t3pos){

                    nodes_t3_t1 = cityQty -(t1pos - t3pos - 1);

                  }

                  for(int k=0;k<nodes_t3_t1;k++){

                    newRoute[newIdx] = route[Math.floorMod(t3pos - k,cityQty)];

                    newIdx++;

                  }                 

                  route = Arrays.copyOf(newRoutecityQty);

                  t5t6Break = true;

                  improved = true;                 

                  break;

                }                

              }

             

             

            }

           

          }        

          if(t5t6Breakbreak//break the t3t4 for loop

        }

               

       

       

      }

      //System.out.println(getTSPDist(dist, route));

      nowLoop++;

    }

    bestRoute = Arrays.copyOf(routecityQty);

    return bestRoute;

  }

  /**根据路径中各个城市的位置,获取每个城市在路径数组中的索引号【从0开始编号】

   * @param route 长度为n的一维数组,内容为0n-1之间的乱序,表示TSP问题中各个城市前后关联形成的一种路径

   * @return 一维数组,为0n-1这些数在route中的索引

   * */

  private static int[] getCityPositionFromRoute(int[] route) {

    int cityQty = route.length;

    int[] positions = new int[cityQty];

    for(int i=0;i<cityQty;i++){

      positions[route[i]]=i;

    }

    return positions;

  } 

  /**根据当前的路径信息,生成各条边是否存在于当前路径中的数组

   * @param route 长度为n的一维数组,内容为0n-1之间的乱序,表示TSP问题中各个城市前后关联形成的一种路径

   * @return 行列均为n的二维数组,交叉处为对应行列表示的边是否存在于当前路径,如果在则为1,否则则为0

   * */

  private static int[][] getTheEdgeValue(int[] route) {

    int nroute.length;

    int[][] inEdges = new int[n][n];

    for(int i=0;i<n-1;i++){

      inEdges[route[i]][route[i+1]] =1;

      inEdges[route[i+1]][route[i]] =1;

    }

    inEdges[route[0]][route[n-1]] =1;

    inEdges[route[n-1]][route[0]] =1;   

    return inEdges;

  }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jiannywang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值