代码
package com.dam.heuristic.algorithm.vns.dam.v2;
import java.util.*;
public class VnsApiV2 {
private int GEN_NUM;
private int SEARCH_NUM;
private int CITY_NUM;
private int NUM_OF_NOT_FIND_BETTER_SOLUTION;
private double[][] distanceMatrix;
public VnsApiV2(int genNum, int searchNum, int numOfNotFindBetterSolution, double[][] distanceMatrix) {
this.GEN_NUM = genNum;
this.SEARCH_NUM = searchNum;
this.NUM_OF_NOT_FIND_BETTER_SOLUTION = numOfNotFindBetterSolution;
this.distanceMatrix = distanceMatrix;
this.CITY_NUM = distanceMatrix[0].length;
}
public int[] solve() {
long startTime = System.currentTimeMillis();
int[] localSequence = new int[this.distanceMatrix[0].length];
int[] bestSequence;
double bestObjectValue;
this.generateInitialSequence(localSequence);
bestSequence = localSequence.clone();
bestObjectValue = this.getObjectValue(bestSequence);
int numOfNotFindBetterSolution = 0;
for (int iterations = 0; iterations < this.GEN_NUM; iterations++) {
if (numOfNotFindBetterSolution>this.NUM_OF_NOT_FIND_BETTER_SOLUTION){
break;
}
int k = 1;
boolean isFindBetterSolution = false;
while (true) {
if (k == 1) {
localSequence = this.generateNewSequenceByReverseTwoElement(bestSequence);
} else if (k == 2) {
localSequence = this.perturbation(bestSequence);
} else {
break;
}
localSequence = this.variableNeighborhoodDescent(localSequence);
double localObjectValue = this.getObjectValue(localSequence);
if (localObjectValue < bestObjectValue) {
bestObjectValue = localObjectValue;
bestSequence = localSequence.clone();
k = 0;
isFindBetterSolution = true;
System.out.println("最优目标函数值:" + bestObjectValue);
System.out.println("计算时间为:" + (System.currentTimeMillis() - startTime) * 1.0 / 1000 + "s");
}
k++;
}
if (isFindBetterSolution == true) {
numOfNotFindBetterSolution = 0;
} else {
numOfNotFindBetterSolution++;
}
}
System.out.println("最优目标函数值:" + bestObjectValue);
System.out.println("最优解对应序列:" + Arrays.toString(bestSequence));
System.out.println("计算时间为:" + (System.currentTimeMillis() - startTime) * 1.0 / 1000 + "s");
return bestSequence;
}
private int[] variableNeighborhoodDescent(int[] localSequence) {
double localObjectValue = this.getObjectValue(localSequence);
int l = 1;
while (true) {
if (l == 1) {
for (int i = 0; i < SEARCH_NUM; i++) {
int[] tempSequence = this.generateNewSequenceBySwapTwoElement(localSequence);
double tempObjectValue = this.getObjectValue(tempSequence);
if (tempObjectValue < localObjectValue) {
localSequence = tempSequence.clone();
localObjectValue = tempObjectValue;
l = 0;
}
}
} else if (l == 2) {
for (int i = 0; i < SEARCH_NUM; i++) {
int[] tempSequence = this.insertElementToAnotherPosition(localSequence);
double tempObjectValue = this.getObjectValue(tempSequence);
if (tempObjectValue < localObjectValue) {
localSequence = tempSequence.clone();
localObjectValue = tempObjectValue;
l = 0;
}
}
} else {
break;
}
l++;
}
return localSequence;
}
private int[] generateNewSequenceByReverseTwoElement(int[] sequence) {
int[] newSequence = sequence.clone();
int temp;
Random random = new Random();
int indexI = random.nextInt(sequence.length);
int indexJ = random.nextInt(sequence.length);
while (indexI == indexJ) {
indexJ = random.nextInt(sequence.length);
}
if (indexJ < indexI) {
temp = indexI;
indexI = indexJ;
indexJ = temp;
}
while (indexI < indexJ) {
temp = newSequence[indexI];
newSequence[indexI] = newSequence[indexJ];
newSequence[indexJ] = temp;
indexI++;
indexJ--;
}
return newSequence;
}
private int[] generateNewSequenceBySwapTwoElement(int[] sequence) {
int[] sequenceClone = sequence.clone();
Random random = new Random();
int i = random.nextInt(sequence.length);
int j = random.nextInt(sequence.length);
while (i == j) {
j = random.nextInt(sequence.length);
}
int temp = sequenceClone[i];
sequenceClone[i] = sequenceClone[j];
sequenceClone[j] = temp;
return sequenceClone;
}
private int[] insertElementToAnotherPosition(int[] sequence) {
Random random = new Random();
int index1 = random.nextInt(sequence.length);
int index2 = random.nextInt(sequence.length);
int type = index1 < index2 ? 0 : 1;
int[] sequenceClone = sequence.clone();
if (type == 0) {
int moveElement = sequenceClone[index1];
for (int i = index1 + 1; i <= index2; i++) {
sequenceClone[i - 1] = sequenceClone[i];
}
sequenceClone[index2] = moveElement;
} else {
int moveElement = sequenceClone[index1];
for (int i = index1; i > index2; i--) {
sequenceClone[i] = sequenceClone[i - 1];
}
sequenceClone[index2] = moveElement;
}
return sequenceClone;
}
private int[] perturbation(int[] bestSequence) {
Random random = new Random();
int[] newSequence = new int[bestSequence.length];
int elementNumInOneGroup = (this.CITY_NUM - 2) / 3;
int[] indexArr = new int[5];
indexArr[0] = 0;
indexArr[1] = random.nextInt(elementNumInOneGroup) + 1;
indexArr[2] = random.nextInt(elementNumInOneGroup) + elementNumInOneGroup + 1;
indexArr[3] = random.nextInt(elementNumInOneGroup) + elementNumInOneGroup * 2 + 1;
indexArr[4] = this.CITY_NUM;
List<Integer> groupCodeList = new ArrayList<>();
Collections.addAll(groupCodeList, 0, 1, 2, 3);
Collections.shuffle(groupCodeList);
int index = 0;
for (int i = 0; i < groupCodeList.size(); i++) {
for (int j = indexArr[groupCodeList.get(i)]; j < indexArr[groupCodeList.get(i) + 1]; j++) {
newSequence[index] = bestSequence[j];
index++;
}
}
return newSequence;
}
private void generateInitialSequence(int[] sequence) {
HashSet<Integer> sequenceSet = new HashSet<>();
for (int i = 1; i < sequence.length; i++) {
sequenceSet.add(i);
}
sequence[0] = 0;
for (int i = 1; i < sequence.length; i++) {
double smallDistance = Double.MAX_VALUE;
int curCity = 0;
for (Integer j : sequenceSet) {
if (this.distanceMatrix[sequence[i - 1]][j] < smallDistance && j != sequence[i - 1]) {
smallDistance = this.distanceMatrix[sequence[i - 1]][j];
curCity = j;
}
}
sequence[i] = curCity;
sequenceSet.remove(curCity);
}
}
private double getObjectValue(int[] sequence) {
double objectValue = 0;
for (int i = 0; i < sequence.length - 1; i++) {
objectValue += this.distanceMatrix[sequence[i]][sequence[i + 1]];
}
objectValue += this.distanceMatrix[sequence[0]][sequence[sequence.length - 1]];
return objectValue;
}
}
测试
package com.dam.heuristic.algorithm.vns.dam;
import com.dam.heuristic.algorithm.vns.dam.v1.VnsApiV1;
import com.dam.heuristic.algorithm.vns.dam.v2.VnsApiV2;
import java.io.File;
import java.io.FileInputStream;
public class VnsMainRun {
public static void main(String[] args) throws Exception {
double[][] distanceMatrix;
double[][] cityPositionArr;
String data = read(new File("src/main/java/com/data/tsp/att48.txt"), "GBK");
String[] cityDataArr = data.split("\n");
distanceMatrix = new double[cityDataArr.length][cityDataArr.length];
cityPositionArr = new double[cityDataArr.length][2];
for (int i = 0; i < cityDataArr.length; i++) {
String[] city1Arr = cityDataArr[i].split(" ");
cityPositionArr[i][0] = Double.valueOf(city1Arr[1]);
cityPositionArr[i][1] = Double.valueOf(city1Arr[2]);
int cityOne = Integer.valueOf(city1Arr[0]);
for (int j = 0; j < i; j++) {
String[] city2Arr = cityDataArr[j].split(" ");
int cityTwo = Integer.valueOf(city2Arr[0]);
if (cityOne == cityTwo) {
distanceMatrix[cityOne - 1][cityTwo - 1] = 0;
} else {
distanceMatrix[cityOne - 1][cityTwo - 1] = getDistance(Double.valueOf(city1Arr[1]), Double.valueOf(city1Arr[2]), Double.valueOf(city2Arr[1]), Double.valueOf(city2Arr[2]));
distanceMatrix[cityTwo - 1][cityOne - 1] = distanceMatrix[cityOne - 1][cityTwo - 1];
}
}
}
VnsApiV2 vnsApiV2 = new VnsApiV2(3000, 100, 100000, distanceMatrix);
vnsApiV2.solve();
}
private static double getDistance(double x1, double y1, double x2, double y2) {
return Math.sqrt((Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)) / 10);
}
private static String read(File f, String charset) throws Exception {
FileInputStream fstream = new FileInputStream(f);
try {
int fileSize = (int) f.length();
if (fileSize > 1024 * 512) {
throw new Exception("File too large to read! size=" + fileSize);
}
byte[] buffer = new byte[fileSize];
fstream.read(buffer);
return new String(buffer, charset);
} finally {
try {
fstream.close();
} catch (Exception e) {
}
}
}
}
结果
att48
最优目标函数值:10745.961500968939
最优解对应序列:[19, 11, 14, 32, 45, 35, 29, 42, 16, 26, 18, 36, 5, 27, 6, 17, 43, 30, 37, 7, 0, 8, 39, 2, 21, 15, 40, 33, 47, 4, 28, 1, 41, 25, 3, 34, 44, 9, 23, 31, 38, 20, 12, 24, 13, 22, 10, 46]
计算时间为:0.688s
随机生成500城市