Skip to content

Commit b071a9e

Browse files
add Traveling Salesman Problem implementation
1 parent 834850e commit b071a9e

File tree

2 files changed

+277
-0
lines changed

2 files changed

+277
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package com.thealgorithms.graph;
2+
3+
import java.util.ArrayList;
4+
import java.util.Arrays;
5+
import java.util.Collections;
6+
import java.util.List;
7+
8+
/**
9+
* This class provides solutions to the Traveling Salesman Problem (TSP) using both brute-force and dynamic programming approaches.
10+
* For more information, see <a href="https://en.wikipedia.org/wiki/Travelling_salesman_problem">Wikipedia</a>.
11+
* @author <a href="https://github.com/DenizAltunkapan">Deniz Altunkapan</a>
12+
*/
13+
public class TravelingSalesman {
14+
15+
/**
16+
* Solves the Traveling Salesman Problem (TSP) using brute-force approach.
17+
* This method generates all possible permutations of cities, calculates the total distance for each route, and returns the shortest distance found.
18+
*
19+
* @param distanceMatrix A square matrix where element [i][j] represents the distance from city i to city j.
20+
* @return The shortest possible route distance visiting all cities exactly once and returning to the starting city.
21+
*/
22+
public static int bruteForce(int[][] distanceMatrix) {
23+
if (distanceMatrix.length <= 1) {
24+
return 0;
25+
}
26+
27+
List<Integer> cities = new ArrayList<>();
28+
for (int i = 1; i < distanceMatrix.length; i++) {
29+
cities.add(i);
30+
}
31+
32+
List<List<Integer>> permutations = generatePermutations(cities);
33+
int minDistance = Integer.MAX_VALUE;
34+
35+
for (List<Integer> permutation : permutations) {
36+
List<Integer> route = new ArrayList<>();
37+
route.add(0);
38+
route.addAll(permutation);
39+
int currentDistance = calculateDistance(distanceMatrix, route);
40+
if (currentDistance < minDistance) {
41+
minDistance = currentDistance;
42+
}
43+
}
44+
45+
return minDistance;
46+
}
47+
48+
/**
49+
* Computes the total distance of a given route.
50+
*
51+
* @param distanceMatrix A square matrix where element [i][j] represents the
52+
* distance from city i to city j.
53+
* @param route A list representing the order in which the cities are visited.
54+
* @return The total distance of the route, or Integer.MAX_VALUE if the route is invalid.
55+
*/
56+
public static int calculateDistance(int[][] distanceMatrix, List<Integer> route) {
57+
int distance = 0;
58+
for (int i = 0; i < route.size() - 1; i++) {
59+
int d = distanceMatrix[route.get(i)][route.get(i + 1)];
60+
if (d == Integer.MAX_VALUE) {
61+
return Integer.MAX_VALUE;
62+
}
63+
distance += d;
64+
}
65+
int returnDist = distanceMatrix[route.get(route.size() - 1)][route.get(0)];
66+
return (returnDist == Integer.MAX_VALUE) ? Integer.MAX_VALUE : distance + returnDist;
67+
}
68+
69+
/**
70+
* Generates all permutations of a given list of cities.
71+
*
72+
* @param cities A list of cities to permute.
73+
* @return A list of all possible permutations.
74+
*/
75+
private static List<List<Integer>> generatePermutations(List<Integer> cities) {
76+
List<List<Integer>> permutations = new ArrayList<>();
77+
permute(cities, 0, permutations);
78+
return permutations;
79+
}
80+
81+
/**
82+
* Recursively generates permutations using backtracking.
83+
*
84+
* @param arr The list of cities.
85+
* @param k The current index in the permutation process.
86+
* @param output The list to store generated permutations.
87+
*/
88+
private static void permute(List<Integer> arr, int k, List<List<Integer>> output) {
89+
if (k == arr.size()) {
90+
output.add(new ArrayList<>(arr));
91+
return;
92+
}
93+
for (int i = k; i < arr.size(); i++) {
94+
Collections.swap(arr, i, k);
95+
permute(arr, k + 1, output);
96+
Collections.swap(arr, i, k);
97+
}
98+
}
99+
100+
/**
101+
* Solves the Traveling Salesman Problem (TSP) using dynamic programming with the Held-Karp algorithm.
102+
*
103+
* @param distanceMatrix A square matrix where element [i][j] represents the distance from city i to city j.
104+
* @return The shortest possible route distance visiting all cities exactly once and returning to the starting city.
105+
* @throws IllegalArgumentException if the input matrix is not square.
106+
*/
107+
public static int dynamicProgramming(int[][] distanceMatrix) {
108+
if (distanceMatrix.length == 0) {
109+
return 0;
110+
}
111+
int n = distanceMatrix.length;
112+
113+
for (int[] row : distanceMatrix) {
114+
if (row.length != n) {
115+
throw new IllegalArgumentException("Matrix must be square");
116+
}
117+
}
118+
119+
int[][] dp = new int[n][1 << n];
120+
for (int[] row : dp) {
121+
Arrays.fill(row, Integer.MAX_VALUE);
122+
}
123+
dp[0][1] = 0;
124+
125+
for (int mask = 1; mask < (1 << n); mask++) {
126+
for (int u = 0; u < n; u++) {
127+
if ((mask & (1 << u)) == 0 || dp[u][mask] == Integer.MAX_VALUE) {
128+
continue;
129+
}
130+
for (int v = 0; v < n; v++) {
131+
if ((mask & (1 << v)) != 0 || distanceMatrix[u][v] == Integer.MAX_VALUE) {
132+
continue;
133+
}
134+
int newMask = mask | (1 << v);
135+
dp[v][newMask] = Math.min(dp[v][newMask], dp[u][mask] + distanceMatrix[u][v]);
136+
}
137+
}
138+
}
139+
140+
int minDistance = Integer.MAX_VALUE;
141+
int fullMask = (1 << n) - 1;
142+
for (int i = 1; i < n; i++) {
143+
if (dp[i][fullMask] != Integer.MAX_VALUE && distanceMatrix[i][0] != Integer.MAX_VALUE) {
144+
minDistance = Math.min(minDistance, dp[i][fullMask] + distanceMatrix[i][0]);
145+
}
146+
}
147+
148+
return minDistance == Integer.MAX_VALUE ? 0 : minDistance;
149+
}
150+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package com.thealgorithms.graph;
2+
3+
import static org.junit.jupiter.api.Assertions.*;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
public class TravelingSalesmanTest {
8+
9+
// Test Case 1: A simple distance matrix with 4 cities
10+
@Test
11+
public void testBruteForceSimple() {
12+
int[][] distanceMatrix = {{0, 10, 15, 20}, {10, 0, 35, 25}, {15, 35, 0, 30}, {20, 25, 30, 0}};
13+
int expectedMinDistance = 80;
14+
int result = TravelingSalesman.bruteForce(distanceMatrix);
15+
assertEquals(expectedMinDistance, result);
16+
}
17+
18+
@Test
19+
public void testDynamicProgrammingSimple() {
20+
int[][] distanceMatrix = {{0, 10, 15, 20}, {10, 0, 35, 25}, {15, 35, 0, 30}, {20, 25, 30, 0}};
21+
int expectedMinDistance = 80;
22+
int result = TravelingSalesman.dynamicProgramming(distanceMatrix);
23+
assertEquals(expectedMinDistance, result);
24+
}
25+
26+
// Test Case 2: A distance matrix with 3 cities
27+
@Test
28+
public void testBruteForceThreeCities() {
29+
int[][] distanceMatrix = {{0, 10, 15}, {10, 0, 35}, {15, 35, 0}};
30+
int expectedMinDistance = 60;
31+
int result = TravelingSalesman.bruteForce(distanceMatrix);
32+
assertEquals(expectedMinDistance, result);
33+
}
34+
35+
@Test
36+
public void testDynamicProgrammingThreeCities() {
37+
int[][] distanceMatrix = {{0, 10, 15}, {10, 0, 35}, {15, 35, 0}};
38+
int expectedMinDistance = 60;
39+
int result = TravelingSalesman.dynamicProgramming(distanceMatrix);
40+
assertEquals(expectedMinDistance, result);
41+
}
42+
43+
// Test Case 3: A distance matrix with 5 cities (larger input)
44+
@Test
45+
public void testBruteForceFiveCities() {
46+
int[][] distanceMatrix = {{0, 2, 9, 10, 1}, {2, 0, 6, 5, 8}, {9, 6, 0, 4, 3}, {10, 5, 4, 0, 7}, {1, 8, 3, 7, 0}};
47+
int expectedMinDistance = 15;
48+
int result = TravelingSalesman.bruteForce(distanceMatrix);
49+
assertEquals(expectedMinDistance, result);
50+
}
51+
52+
@Test
53+
public void testDynamicProgrammingFiveCities() {
54+
int[][] distanceMatrix = {{0, 2, 9, 10, 1}, {2, 0, 6, 5, 8}, {9, 6, 0, 4, 3}, {10, 5, 4, 0, 7}, {1, 8, 3, 7, 0}};
55+
int expectedMinDistance = 15;
56+
int result = TravelingSalesman.dynamicProgramming(distanceMatrix);
57+
assertEquals(expectedMinDistance, result);
58+
}
59+
60+
// Test Case 4: A distance matrix with 2 cities (simple case)
61+
@Test
62+
public void testBruteForceTwoCities() {
63+
int[][] distanceMatrix = {{0, 1}, {1, 0}};
64+
int expectedMinDistance = 2;
65+
int result = TravelingSalesman.bruteForce(distanceMatrix);
66+
assertEquals(expectedMinDistance, result);
67+
}
68+
69+
@Test
70+
public void testDynamicProgrammingTwoCities() {
71+
int[][] distanceMatrix = {{0, 1}, {1, 0}};
72+
int expectedMinDistance = 2;
73+
int result = TravelingSalesman.dynamicProgramming(distanceMatrix);
74+
assertEquals(expectedMinDistance, result);
75+
}
76+
77+
// Test Case 5: A distance matrix with identical distances
78+
@Test
79+
public void testBruteForceEqualDistances() {
80+
int[][] distanceMatrix = {{0, 10, 10, 10}, {10, 0, 10, 10}, {10, 10, 0, 10}, {10, 10, 10, 0}};
81+
int expectedMinDistance = 40;
82+
int result = TravelingSalesman.bruteForce(distanceMatrix);
83+
assertEquals(expectedMinDistance, result);
84+
}
85+
86+
@Test
87+
public void testDynamicProgrammingEqualDistances() {
88+
int[][] distanceMatrix = {{0, 10, 10, 10}, {10, 0, 10, 10}, {10, 10, 0, 10}, {10, 10, 10, 0}};
89+
int expectedMinDistance = 40;
90+
int result = TravelingSalesman.dynamicProgramming(distanceMatrix);
91+
assertEquals(expectedMinDistance, result);
92+
}
93+
94+
// Test Case 6: A distance matrix with only one city
95+
@Test
96+
public void testBruteForceOneCity() {
97+
int[][] distanceMatrix = {{0}};
98+
int expectedMinDistance = 0;
99+
int result = TravelingSalesman.bruteForce(distanceMatrix);
100+
assertEquals(expectedMinDistance, result);
101+
}
102+
103+
@Test
104+
public void testDynamicProgrammingOneCity() {
105+
int[][] distanceMatrix = {{0}};
106+
int expectedMinDistance = 0;
107+
int result = TravelingSalesman.dynamicProgramming(distanceMatrix);
108+
assertEquals(expectedMinDistance, result);
109+
}
110+
111+
// Test Case 7: Distance matrix with large numbers
112+
@Test
113+
public void testBruteForceLargeNumbers() {
114+
int[][] distanceMatrix = {{0, 1000000, 2000000}, {1000000, 0, 1500000}, {2000000, 1500000, 0}};
115+
int expectedMinDistance = 4500000;
116+
int result = TravelingSalesman.bruteForce(distanceMatrix);
117+
assertEquals(expectedMinDistance, result);
118+
}
119+
120+
@Test
121+
public void testDynamicProgrammingLargeNumbers() {
122+
int[][] distanceMatrix = {{0, 1000000, 2000000}, {1000000, 0, 1500000}, {2000000, 1500000, 0}};
123+
int expectedMinDistance = 4500000;
124+
int result = TravelingSalesman.dynamicProgramming(distanceMatrix);
125+
assertEquals(expectedMinDistance, result);
126+
}
127+
}

0 commit comments

Comments
 (0)