I was tasked with implementing the nearest neighbour algorithm for the travelling salesman problem. It was said that the method should try starting from every city and return the best tour found. According to the auto-marking program, my implementation works correctly for the most basic case, but only works partially for all more advanced cases.
I don't understand where I went wrong, and am seeking a review of my code for correctness. I am keen to find out where I went wrong and what the correct approach would be.
My Java code is as follows:
/*
* Returns the shortest tour found by exercising the NN algorithm
* from each possible starting city in table.
* table[i][j] == table[j][i] gives the cost of travel between City i and City j.
*/
public static int[] tspnn(double[][] table) {
// number of vertices
int numberOfVertices = table.length;
// the Hamiltonian cycle built starting from vertex i
int[] currentHamiltonianCycle = new int[numberOfVertices];
// the lowest total cost Hamiltonian cycle
double lowestTotalCost = Double.POSITIVE_INFINITY;
// the shortest Hamiltonian cycle
int[] shortestHamiltonianCycle = new int[numberOfVertices];
// consider each vertex i as a starting point
for (int i = 0; i < numberOfVertices; i++) {
/*
* Consider all vertices that are reachable from the starting point i,
* thereby creating a new current Hamiltonian cycle.
*/
for (int j = 0; j < numberOfVertices; j++) {
/*
* The modulo of the sum of i and j allows us to account for the fact
* that Java indexes arrays from 0.
*/
currentHamiltonianCycle[j] = (i + j) % numberOfVertices;
}
for (int j = 1; j < numberOfVertices - 1; j++) {
int nextVertex = j;
for (int p = j + 1; p < numberOfVertices; p++) {
if (table[currentHamiltonianCycle[j - 1]][currentHamiltonianCycle[p]] < table[currentHamiltonianCycle[j - 1]][currentHamiltonianCycle[nextVertex]]) {
nextVertex = p;
}
}
int a = currentHamiltonianCycle[nextVertex];
currentHamiltonianCycle[nextVertex] = currentHamiltonianCycle[j];
currentHamiltonianCycle[j] = a;
}
/*
* Find the total cost of the current Hamiltonian cycle.
*/
double currentTotalCost = table[currentHamiltonianCycle[0]][currentHamiltonianCycle[numberOfVertices - 1]];
for (int z = 0; z < numberOfVertices - 1; z++) {
currentTotalCost += table[currentHamiltonianCycle[z]][currentHamiltonianCycle[z + 1]];
}
if (currentTotalCost < lowestTotalCost) {
lowestTotalCost = currentTotalCost;
shortestHamiltonianCycle = currentHamiltonianCycle;
}
}
return shortestHamiltonianCycle;
}
Edit
I've gone through this code with pen and paper for a simple example, and I can't find any problems with the algorithm implementation. Based on this, it seems to me that it should work in the general case.
Edit 2
I have tested my implementation with the following mock example:
double[][] table = {{0, 2.3, 1.8, 4.5}, {2.3, 0, 0.4, 0.1},
{1.8, 0.4, 0, 1.3}, {4.5, 0.1, 1.3, 0}};
It seems to produce the expected output for the nearest neighbour algorithm, which is 3 -> 1 -> 2 -> 0
I am now wondering whether the auto-marking program is incorrect, or whether it's just that my implementation does not work in the general case.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…