算法流程图如下所示:
20个城市的TSP问题,每个城市的坐标如下(data.txt):
60,200 180,200 80,180 140,180 20,160 100,160 200,160 140,140 40,120 100,120 180,100 60,80 120,80 180,60 20,40 100,40 200,40 20,20 60,20 160,20
package tsp.tabusearch;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class Data {
static int cityNum;
//读文件
public static int[][] readFile(String filename) {
int[][] xy = new int[cityNum][cityNum];
try {
BufferedReader bf = new BufferedReader(new FileReader(filename));
for (int i = 0; i < cityNum; i++) {
String[] coordinate = bf.readLine().split(",");
xy[i][0] = Integer.parseInt(coordinate[0]);
xy[0][i] = Integer.parseInt(coordinate[1]);
}
bf.close();
} catch (IOException e) {
e.printStackTrace();
}
int[][] distance = new int[cityNum][cityNum];
for (int i = 0; i < cityNum; i++) {
distance[i][i] = 0;
for (int j = 0; j < cityNum; j++) {
distance[i][j] = distance[j][i] = (int) Math.sqrt(Math.abs((xy[i][0] - xy[j][0])) * Math.abs((xy[i][0] - xy[j][0]))
+ Math.abs((xy[0][i] - xy[0][j])) * Math.abs((xy[i][0] - xy[j][0])));
}
}
return distance;
}
}
package tsp.tabusearch; import java.util.HashSet; import java.util.Iterator; public class UtilMeth { /** * 产生指定范围的随机数组 *
* HashSet + 递归 * * @param min 指定范围最小值 * @param max 指定范围最大值 */ //产生一个不重复的随机数组 public static int[] randArr(int min, int max) { if (max < min) throw new IllegalArgumentException("error param!"); int[] randArr = new int[max - min]; HashSet
set = new HashSet<>(); gen(min, max, set); // 如果存入的数小于指定生成的个数,则调用递归再生成剩余个数的随机数,如此循环,直到达到指定大小 while (set.size() < max - min) gen(min, max, set);// 递归 Iterator it = set.iterator(); int i = 0; while (it.hasNext()) { randArr[i] = it.next(); i++; } return randArr; } private static void gen(int min, int max, HashSet set) { for (int i = 0; i < max - min; i++) { int num = (int) ((Math.random()) * (max - min)) + min; set.add(num);// 将不同的数存入HashSet中 } } //数组复制 public static void reproduce(int[] route1, int[] route2) { for (int i = 0; i < route2.length; i++) route1[i] = route2[i]; } //数组复制 public static int[] reproduce(int[] route) { int[] route_copy = new int[route.length]; reproduce(route_copy, route); return route_copy; } }
package tsp.tabusearch;
import static net.mindview.util.Print.*;
import java.util.Arrays;
import java.util.Random;
public class TabuSearch {
public int cityNum;
public int[] route;
int[] optimalRoute;
int tableLen;
int[][] tabuTable;
final int MAX_GEN = 1000;
final int UMG_SCOP = 200;
public Random rand;
TabuSearch(int cityNum) {
this.cityNum = cityNum;
Data.cityNum = cityNum;
route = new int[cityNum];
optimalRoute = new int[cityNum];
int tableLen = 20;
tabuTable = new int[tableLen][cityNum];
rand = new Random(System.currentTimeMillis());
}
//生成一个初始解
public void initGroup() {
route = UtilMeth.randArr(0, cityNum).clone();
print("初始路径:" + Arrays.toString(route));
print("初始距离:" + evaluation(route));
}
//评价函数
int evaluation(int[] route) {
int[][] dist = Data.readFile("D:\\Users\\36297\\JavaWorkspace\\algori\\src\\tsp\\geneticalgori\\data.txt");
int len = 0;
for (int i = 1; i < cityNum; i++)
len += dist[route[i - 1]][route[i]];
len += dist[route[cityNum - 1]][route[0]];
return len;
}
//邻域移动
void moveOperator(int[] route) {
int rand1 = rand.nextInt(20);
int rand2 = rand.nextInt(20);
int city1 = route[rand1];
int city2 = route[rand2];
route[rand2] = city1;
route[rand1] = city2;
}
//特赦准则(藐视准则、破禁准则)
boolean aspirationCriterion(int[] route) {
boolean flag = false;
outer:
for (int i = 0; i < tableLen; i++) {
for (int j = 0; j < cityNum; j++) {
if (route[j] == tabuTable[i][j]) {
flag = true;
break outer;
}
}
}
return flag;
}
//更新禁忌表
void updateTabuTable(int[] neighbor) {
int i, j, k;
//删除禁忌表第一个编码,后面编码往前移动
for (i = 0; i < tableLen - 1; i++) {
for (j = 0; j < cityNum; j++)
tabuTable[i][j] = tabuTable[i + 1][j];
//新的编码加入禁忌表
for (k = 0; k < cityNum; k++) {
tabuTable[tableLen - 1][k] = neighbor[k];
}
}
}
void solution() {
initGroup();
int bestEval = evaluation(route);
UtilMeth.reproduce(optimalRoute, route);
for (int gen = 0; gen < MAX_GEN; gen++) {
int neighEval = Integer.MAX_VALUE;
int[] neigh = new int[cityNum];
for (int umg = 0; umg < UMG_SCOP; umg++) {
int[] newRoute = UtilMeth.reproduce(route);
moveOperator(newRoute);//邻域移动产生新解
if (!aspirationCriterion(newRoute)) {
int newEval = evaluation(newRoute);
if (newEval < neighEval) { //新解优于当前解
UtilMeth.reproduce(neigh, newRoute);
neighEval = newEval;
}
}
}
if (neighEval < bestEval) {
UtilMeth.reproduce(route, neigh);
bestEval = neighEval;
}
updateTabuTable(neigh);
}
print("最终路径:" + Arrays.toString(route));
print("最终距离:" + bestEval);
}
}
package tsp.tabusearch;
import static net.mindview.util.Print.print;
public class Test {
public static void main(String[] args) {
TabuSearch ts = new TabuSearch(20);
long t1 = System.currentTimeMillis();
ts.solution();
long t2 = System.currentTimeMillis();
print("求解耗时:"+(t2 - t1)/1000 +"s");
}
}
3次运行结果如下:
初始路径:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
初始距离:1854
最终路径:[2, 1, 10, 13, 15, 5, 9, 7, 3, 6, 0, 16, 19, 12, 8, 4, 14, 17, 18, 11]
最终距离:645
求解耗时:13s
初始路径:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
初始距离:1854
最终路径:[10, 1, 0, 6, 5, 9, 7, 3, 2, 4, 8, 11, 12, 13, 16, 15, 14, 17, 18, 19]
最终距离:886
求解耗时:13s
初始路径:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
初始距离:1854
最终路径:[6, 0, 1, 3, 7, 5, 2, 4, 8, 9, 10, 13, 12, 11, 18, 17, 14, 15, 19, 16]
最终距离:762
求解耗时:13s