-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathq2_answer.py
More file actions
189 lines (131 loc) · 4.23 KB
/
Copy pathq2_answer.py
File metadata and controls
189 lines (131 loc) · 4.23 KB
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# Algorithm Design Foundations
#
# Final Exam, Question 2
#
# Student Name: Hamed Araab
# Student Number: 9925003
from heapq import heappop, heappush
class TSPSolver:
def __init__(self, arcs, nodes_count):
self._arcs = arcs
self._nodes_count = nodes_count
self._graph = self._get_graph()
self._all_min_costs = {node: self._get_min_costs(node) for node in self._graph}
@property
def arcs(self):
return self._arcs
@property
def nodes_count(self):
return self._nodes_count
@property
def graph(self):
return self._graph
def _get_graph(self):
"""
Returns a graph using `arcs` and `nodes_count`.
### Example:
Input:
```
arcs = {(1, 2, 1), (3, 1, 1)}
nodes_count = 3
```
Output:
```
graph = {
1: {(2, 1), (3, 1)}
2: {},
3: {(1, 1)},
}
```
"""
return {
node: set(
(target, cost) for start, target, cost in self._arcs if start == node
)
for node in range(1, self._nodes_count + 1)
}
def _get_min_costs(self, start_node):
"""
Returns the minimum cost of traveling from `start_node` to other nodes of the
`graph` as a `dict`.
### Example:
Input:
```
graph = {
1: {(2, 1), (3, 3)}
2: {(3, 1)},
3: {},
}
start_node = 1
```
Output:
```
min_costs = {
2: 1,
3: 2,
}
```
### Notes:
- This function uses the Dijkstra and Heap Queue (Priority Queue)
algorithms.
"""
min_costs = {
node: 0.0 if node == start_node else float("inf") for node in self._graph
}
visited_nodes = set()
visiting_queue = [(0.0, start_node)]
while visiting_queue:
current_cost, current_node = heappop(visiting_queue)
if current_node in visited_nodes:
continue
for neighbor, cost in self._graph[current_node]:
new_cost = current_cost + cost
if new_cost < min_costs[neighbor]:
min_costs[neighbor] = new_cost
heappush(visiting_queue, (new_cost, neighbor))
visited_nodes.add(current_node)
return min_costs
def get_min_cost_of_tour(self, selected_nodes):
"""
Returns the minimum cost of touring `selected_nodes`.
### Notes:
- The staring and ending node (aka depot) of the tour is the first node in
`selected_nodes`.
"""
def backtrack(current_node, remaining_nodes, total_cost):
if not remaining_nodes:
return total_cost + self._all_min_costs[current_node][start_node]
cost = float("inf")
for node in remaining_nodes:
new_cost = backtrack(
node,
remaining_nodes - {node},
total_cost + self._all_min_costs[current_node][node],
)
cost = min(cost, new_cost)
return cost
start_node = selected_nodes[0]
remaining_nodes = set(selected_nodes[1:])
total_cost = backtrack(start_node, remaining_nodes, 0.0)
if total_cost == float("inf"):
return -1
return total_cost
def main():
# Start of getting part one of user inputs.
nodes_count, arcs_count = tuple(map(int, input().split(" ")))
arcs = set()
for _ in range(arcs_count):
user_input = input().split(" ")
arc = (int(user_input[0]), int(user_input[1]), float(user_input[2]))
arcs.add(arc)
# End of getting part one of user inputs.
tsp_solver = TSPSolver(arcs, nodes_count)
print("Ready")
# Start of getting part two user inputs.
travels_count = int(input())
travels = [list(map(int, input().split(" ")))[1:] for _ in range(travels_count)]
# End of getting part two user inputs.
for selected_nodes in travels:
print(tsp_solver.get_min_cost_of_tour(selected_nodes))
if __name__ == "__main__":
main()