1
1
#!/usr/bin/env python3
2
2
3
-
4
3
def tsp (distances : list [list [int ]]) -> int :
5
4
"""
6
- Solves the Travelling Salesman Problem (TSP)
7
- using dynamic programming and bitmasking.
8
-
9
- Args:
10
- distances: 2D list where distances[i][j]
11
- is the distance between city i and city j.
12
-
13
- Returns:
14
- Minimum cost to complete the tour visiting all cities.
15
-
16
- Raises:
17
- ValueError: If any distance is negative.
18
-
19
- >>> tsp([[0, 10, 15, 20], [10, 0, 35, 25], [15, 35, 0, 30], [20, 25, 30, 0]])
20
- 80
21
- >>> tsp([[0, 29, 20, 21], [29, 0, 15, 17], [20, 15, 0, 28], [21, 17, 28, 0]])
22
- 69
23
- >>> tsp([[0, 10, -15, 20], [10, 0, 35, 25], [15, 35, 0, 30], [20, 25, 30, 0]])
24
- # doctest: +ELLIPSIS
25
- Traceback (most recent call last):
26
- ...
27
- ValueError: Distance cannot be negative
5
+ Solves the Travelling Salesman Problem (TSP)
6
+ using dynamic programming and bitmasking.
7
+
8
+ Args:
9
+ distances: 2D list where distances[i][j]
10
+ is the distance between city i and city j.
11
+
12
+ Returns:
13
+ Minimum cost to complete the tour visiting all cities.
14
+
15
+ Raises:
16
+ ValueError: If any distance is negative.
17
+
18
+ >>> tsp([[0, 10, 15, 20], [10, 0, 35, 25], [15, 35, 0, 30],
19
+ [20, 25, 30, 0]])
20
+ 80
21
+ >>> tsp([[0, 29, 20, 21], [29, 0, 15, 17], [20, 15, 0, 28],
22
+ [21, 17, 28, 0]])
23
+ 69
24
+ >>> tsp([[0, 10, -15, 20], [10, 0, 35, 25], [15, 35, 0, 30],
25
+ [20, 25, 30, 0]]) # doctest: +ELLIPSIS
26
+ Traceback (most recent call last):
27
+ ...
28
+ ValueError: Distance cannot be negative
28
29
"""
29
30
n = len (distances )
30
31
if any (distances [i ][j ] < 0 for i in range (n ) for j in range (n )):
@@ -40,21 +41,16 @@ def visit(city: int, mask: int) -> int:
40
41
return distances [city ][0 ] # Return to the starting city
41
42
if memo [city ][mask ] != - 1 : # Return cached result if exists
42
43
return memo [city ][mask ]
43
-
44
- min_cost = float ("inf" ) # Use infinity for initial comparison
44
+ min_cost = float ('inf' ) # Use infinity for initial comparison
45
45
for next_city in range (n ):
46
46
if not (mask & (1 << next_city )): # If unvisited
47
47
new_cost = distances [city ][next_city ] + visit (
48
48
next_city , mask | (1 << next_city )
49
49
)
50
50
min_cost = min (min_cost , new_cost )
51
- memo [city ][mask ] = min_cost # Store result in the memoization table
52
- return min_cost
53
-
54
- return visit (0 , 1 ) # Start from city 0 with only city 0 visited
55
-
56
-
51
+ memo [city ][mask ] = int (min_cost ) # Store result as an integer
52
+ return memo [city ][mask ] # Return the cached result
53
+ return visit (0 , 1 ) # Start from city 0 with city 0 visited
57
54
if __name__ == "__main__" :
58
55
import doctest
59
-
60
56
doctest .testmod ()
0 commit comments