|
| 1 | +""" |
| 2 | +Travelling Salesman Problem: |
| 3 | +An Exact Dynamic Programming Solution in Python |
| 4 | +
|
| 5 | +Jessica Yung |
| 6 | +Dec 2018 |
| 7 | +""" |
| 8 | + |
| 9 | +class TravellingSalesman: |
| 10 | + |
| 11 | + def __init__(self, graph, start): |
| 12 | + """Initialise with graph and node you start from. |
| 13 | + :param graph: takes the form of an adjacency matrix |
| 14 | + (suitable since we are given a fully connected graph). |
| 15 | + :param start: an int (index in adj matrix). |
| 16 | + Node you start from doesn't make a difference since this is a tour. |
| 17 | + """ |
| 18 | + self.graph = graph |
| 19 | + self.start = start |
| 20 | + self.nodes = np.arange(len(graph)) |
| 21 | + |
| 22 | + def cost(self, nodes, end): |
| 23 | + if (nodes, end) is in self.cost_dict.keys(): |
| 24 | + return self.cost_dict[(nodes, end)] |
| 25 | + else: |
| 26 | + self.cost_dict[nodes, end] = self.calc_cost(nodes, end) |
| 27 | + return self.cost_dict[nodes, end] |
| 28 | + |
| 29 | + def calc_cost(self, nodes, end): |
| 30 | + if end not in nodes: |
| 31 | + return Exception("Endpoint not in nodes to visit.") |
| 32 | + if len(nodes) == 1: |
| 33 | + return 0 |
| 34 | + if len(nodes) == 2: |
| 35 | + return self.graph[nodes[0], nodes[1]] |
| 36 | + non_end_nodes = nodes.copy().remove(end) |
| 37 | + return min(self.cost(non_end_nodes, j) + self.graph[j, end] for j in non_end_nodes if j != self.start) |
| 38 | + |
| 39 | + def dp(self): |
| 40 | + """Dynamic programming solution to Travelling Salesman problem.""" |
| 41 | + return self.cost(self.nodes, self.start) |
| 42 | + |
| 43 | + |
| 44 | +# test case: |
| 45 | +def create_adj_matrix(dists): |
| 46 | + """dists: (n-1)x(n-1) matrix with (n-1)*n/2 entries |
| 47 | + dists from 0 to 1, 2,...n-1, then dists from 1 to 2,...,n-1. |
| 48 | + cells that don't represent dists are left as zeroes. |
| 49 | + """ |
| 50 | + pass |
| 51 | + |
0 commit comments