Skip to content

Commit 63e4798

Browse files
authored
Create travelling_salesman_problem.py
added travelling salesman problem under dynamic programming
1 parent e9e7c96 commit 63e4798

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""
2+
Given a list of cities and the distances between every pair of cities, the Travelling Salesman Problem (TSP) is to
3+
find the shortest possible route that visits every city exactly once and returns to the starting city.
4+
5+
This problem can be solved using the concept of "DYNAMIC PROGRAMMING".
6+
7+
We use a bitmask to represent which cities have been visited and calculate the minimum cost to complete the tour.
8+
9+
Example - distances = [
10+
[0, 10, 15, 20],
11+
[10, 0, 35, 25],
12+
[15, 35, 0, 30],
13+
[20, 25, 30, 0]
14+
]
15+
Output: 80
16+
"""
17+
18+
from functools import lru_cache
19+
20+
21+
def tsp(distances: list[list[int]]) -> int:
22+
"""
23+
The tsp function solves the Travelling Salesman Problem (TSP) using dynamic programming and bitmasking.
24+
It calculates the minimum cost to visit all cities and return to the starting city.
25+
26+
>>> tsp([[0, 10, 15, 20], [10, 0, 35, 25], [15, 35, 0, 30], [20, 25, 30, 0]])
27+
80
28+
>>> tsp([[0, 29, 20, 21], [29, 0, 15, 17], [20, 15, 0, 28], [21, 17, 28, 0]])
29+
69
30+
>>> tsp([[0, 10, -15, 20], [10, 0, 35, 25], [15, 35, 0, 30], [20, 25, 30, 0]])
31+
Traceback (most recent call last):
32+
...
33+
ValueError: Distance cannot be negative
34+
"""
35+
n = len(distances)
36+
if any(distances[i][j] < 0 for i in range(n) for j in range(n)):
37+
raise ValueError("Distance cannot be negative")
38+
39+
VISITED_ALL = (1 << n) - 1
40+
41+
@lru_cache(None)
42+
def visit(city: int, mask: int) -> int:
43+
"""
44+
Recursively calculate the minimum cost of visiting all cities, starting at 'city' with visited cities encoded in 'mask'.
45+
"""
46+
if mask == VISITED_ALL:
47+
return distances[city][0] # Return to the starting city
48+
49+
min_cost = float('inf')
50+
for next_city in range(n):
51+
if not mask & (1 << next_city): # If the next_city is not visited
52+
new_cost = distances[city][next_city] + visit(next_city, mask | (1 << next_city))
53+
min_cost = min(min_cost, new_cost)
54+
return min_cost
55+
56+
return visit(0, 1) # Start at city 0 with only city 0 visited
57+
58+
59+
if __name__ == "__main__":
60+
import doctest
61+
62+
doctest.testmod()
63+
print(f"{tsp([[0, 10, 15, 20], [10, 0, 35, 25], [15, 35, 0, 30], [20, 25, 30, 0]]) = }")
64+
print(f"{tsp([[0, 29, 20, 21], [29, 0, 15, 17], [20, 15, 0, 28], [21, 17, 28, 0]]) = }")

0 commit comments

Comments
 (0)