-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtravelling_salesman.py
132 lines (112 loc) · 4.44 KB
/
travelling_salesman.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
from termcolor import colored
class TravellingSalesman:
"""
Problem Type: Graph, Travelling Salesman Problem (TSP)
Problem Statement:
Given a graph represented as an adjacency matrix and a starting node, find the shortest possible route that visits each node exactly once and returns to the starting node.
Parameters:
graph (List[List[int]]): The graph represented as an adjacency matrix.
start (int): The starting node for the TSP.
Methods:
__init__(graph, start): Initializes the TSP with the given graph and starting node.
__call__(): Solves the TSP and returns the minimum cost and the path.
__repr__(): Returns a string representation of the TSP instance.
Example:
graph = [
[0, 10, 15, 20],
[10, 0, 35, 25],
[15, 35, 0, 30],
[20, 25, 30, 0]
]
tsp = TravellingSalesman(graph, 0)
tsp() -> (80, [0, 1, 3, 2, 0])
Diagram:
0
/|\
10|15
/ | \
1---|---2
\ | /
25|30
\|/
3
"""
def __init__(self, graph, start):
# Initialize the TSP with the given graph and starting node
self.graph = graph
self.start = start
# Number of nodes in the graph
self.n = len(graph)
# Bitmask representing all nodes visited
self.all_visited = (1 << self.n) - 1
# Memoization table to store the minimum cost for each state
self.memo = [[None] * self.n for _ in range(1 << self.n)]
def __call__(self):
# Solve the TSP and get the minimum cost
min_cost = self._tsp(1 << self.start, self.start)
# Reconstruct the path from the memoization table
path = [self.start] + self._find_path(1 << self.start, self.start)
# Append the starting node to complete the cycle
path.append(self.start)
return min_cost, path
def _tsp(self, mask, pos):
"""
Helper function to solve the TSP using dynamic programming and bit masking.
Parameters:
mask (int): The bitmask representing the set of visited nodes.
pos (int): The current node position.
Returns:
int: The minimum cost to complete the TSP from the current state.
"""
# If all nodes have been visited, return the cost to return to the start node
if mask == self.all_visited:
return self.graph[pos][self.start]
# If the result is already computed, return it
if self.memo[mask][pos] is not None:
return self.memo[mask][pos]
# Initialize the minimum cost to infinity
min_cost = float('inf')
# Try to visit all unvisited nodes and calculate the minimum cost
for city in range(self.n):
if mask & (1 << city) == 0:
new_cost = self.graph[pos][city] + self._tsp(mask | (1 << city), city)
min_cost = min(min_cost, new_cost)
# Store the result in the memoization table
self.memo[mask][pos] = min_cost
return min_cost
def _find_path(self, mask, pos):
"""
Helper function to reconstruct the path of the TSP from the memoization table.
Parameters:
mask (int): The bitmask representing the set of visited nodes.
pos (int): The current node position.
Returns:
List[int]: The path of the TSP from the current state.
"""
# If all nodes have been visited, return the start node
if mask == self.all_visited:
return [self.start]
# Reconstruct the path by finding the next node that matches the minimum cost
for city in range(self.n):
if mask & (1 << city) == 0:
if self.memo[mask][pos] == self.graph[pos][city] + self._tsp(mask | (1 << city), city):
return [city] + self._find_path(mask | (1 << city), city)
return []
def __repr__(self):
return f"TravellingSalesman(graph={self.graph}, start={self.start})"
# Example usage:
graph = [
[0, 10, 15, 20],
[10, 0, 35, 25],
[15, 35, 0, 30],
[20, 25, 30, 0]
]
tsp = TravellingSalesman(graph, 0)
print(colored('-'*100, 'red'))
print(colored(f"Travelling Salesman Problem: {colored(tsp, 'magenta')}", 'magenta'))
min_cost, path = tsp()
print(colored('-'*100, 'red'))
print(colored(f"Minimum cost: {min_cost}", 'green'))
print(colored('-'*100, 'red'))
print(colored(f"Path: {path}", 'red'))
print(colored('-'*100, 'red'))