11def tsp (data ):
2- length = 0
3- visited = [False ] * len (data )
4- paths = []
5-
62 G = build_graph (data )
73 print ("Graph: " , G )
84
@@ -17,26 +13,31 @@ def tsp(data):
1713 minimum_weight_matching (MSTree , G , odd_vertexes )
1814 print ("Minimum weight matching: " , MSTree )
1915
20- eulerian_tour = find_eulerian_tour (MSTree )
21- visited = [False ] * (len (eulerian_tour ) - 1 )
22-
16+ eulerian_tour = find_eulerian_tour (MSTree , G )
2317
2418 print ("Eulerian tour: " , eulerian_tour )
2519
2620 current = eulerian_tour [0 ]
27- paths = [current ]
28- for x in eulerian_tour [1 :]:
29- if not visited [x ]:
30- visited [x ] = True
21+ path = [current ]
22+ visited = [False ] * len (eulerian_tour )
3123
32- paths .append (x )
33- length += G [current ][x ]
24+ length = 0
3425
35- current = x
26+ for v in eulerian_tour [1 :]:
27+ if not visited [v ]:
28+ path .append (v )
29+ visited [v ] = True
3630
37- print ("Result path: " , paths )
31+ length += G [current ][v ]
32+ current = v
33+
34+ path .append (path [0 ])
35+
36+ print ("Result path: " , path )
3837 print ("Result length of the path: " , length )
3938
39+ return length , path
40+
4041
4142def get_length (x1 , y1 , x2 , y2 ):
4243 return ((x1 - x2 ) ** 2 + (y1 - y2 ) ** 2 ) ** (1 / 2 )
@@ -57,31 +58,11 @@ def build_graph(data):
5758
5859
5960class UnionFind :
60- """Union-find data structure.
61-
62- Each unionFind instance X maintains a family of disjoint sets of
63- hashable objects, supporting the following two methods:
64-
65- - X[item] returns a name for the set containing the given item.
66- Each set is named by an arbitrarily-chosen one of its members; as
67- long as the set remains unchanged it will keep the same name. If
68- the item is not yet part of a set in X, a new singleton set is
69- created for it.
70-
71- - X.union(item1, item2, ...) merges the sets containing each item
72- into a single larger set. If any item is not yet part of a set
73- in X, it is added to X as one of the members of the merged set.
74- """
75-
7661 def __init__ (self ):
77- """Create a new empty union-find structure."""
7862 self .weights = {}
7963 self .parents = {}
8064
8165 def __getitem__ (self , object ):
82- """Find and return the name of the set containing the object."""
83-
84- # check for previously unknown object
8566 if object not in self .parents :
8667 self .parents [object ] = object
8768 self .weights [object ] = 1
@@ -100,11 +81,9 @@ def __getitem__(self, object):
10081 return root
10182
10283 def __iter__ (self ):
103- """Iterate through all items ever found or unioned by this structure."""
10484 return iter (self .parents )
10585
10686 def union (self , * objects ):
107- """Find the sets containing the objects and merge them all."""
10887 roots = [self [x ] for x in objects ]
10988 heaviest = max ([(self .weights [r ], r ) for r in roots ])[1 ]
11089 for r in roots :
@@ -145,44 +124,100 @@ def find_odd_vertexes(MST):
145124
146125
147126def minimum_weight_matching (MST , G , odd_vert ):
127+ import random
128+ odd_vert = random .shuffle (odd_vert )
129+
148130 while odd_vert :
149131 v = odd_vert .pop ()
150132 length = float ("inf" )
151133 u = 1
152134 closest = 0
153135 for u in odd_vert :
154- if G [v ][u ] < length :
136+ if v != u and G [v ][u ] < length :
155137 length = G [v ][u ]
156138 closest = u
157139
158140 MST .append ((v , closest , length ))
159141 odd_vert .remove (closest )
160142
161143
162- def find_eulerian_tour (MatchedMSTree ):
163- tour = []
144+ def find_eulerian_tour (MatchedMSTree , G ):
145+ # find neigbours
146+ neighbours = {}
147+ for edge in MatchedMSTree :
148+ if edge [0 ] not in neighbours :
149+ neighbours [edge [0 ]] = []
164150
165- start_vertex = MatchedMSTree [0 ][0 ]
151+ if edge [1 ] not in neighbours :
152+ neighbours [edge [1 ]] = []
166153
167- tour .append (start_vertex )
154+ neighbours [edge [0 ]].append (edge [1 ])
155+ neighbours [edge [1 ]].append (edge [0 ])
156+
157+ # print("Neighbours: ", neighbours)
158+
159+ # finds the hamiltonian circuit
160+ start_vertex = MatchedMSTree [0 ][0 ]
161+ EP = [neighbours [start_vertex ][0 ]]
168162
169163 while len (MatchedMSTree ) > 0 :
170- current_vertex = tour [len (tour ) - 1 ]
171- for edge in MatchedMSTree :
172- if current_vertex in edge :
173- if edge [0 ] == current_vertex :
174- current_vertex = edge [1 ]
175- elif edge [1 ] == current_vertex :
176- current_vertex = edge [0 ]
177- else :
178- # Edit to account for case no tour is possible
179- return False
180-
181- MatchedMSTree .remove (edge )
182- tour .append (current_vertex )
164+ for i , v in enumerate (EP ):
165+ if len (neighbours [v ]) > 0 :
183166 break
184167
185- return tour
168+ while len (neighbours [v ]) > 0 :
169+ w = neighbours [v ][0 ]
170+
171+ remove_edge_from_matchedMST (MatchedMSTree , v , w )
172+
173+ del neighbours [v ][(neighbours [v ].index (w ))]
174+ del neighbours [w ][(neighbours [w ].index (v ))]
175+
176+ i += 1
177+ EP .insert (i , w )
178+
179+ v = w
180+
181+ return EP
182+
183+
184+ def remove_edge_from_matchedMST (MatchedMST , v1 , v2 ):
185+
186+ for i , item in enumerate (MatchedMST ):
187+ if (item [0 ] == v2 and item [1 ] == v1 ) or (item [0 ] == v1 and item [1 ] == v2 ):
188+ del MatchedMST [i ]
189+
190+ return MatchedMST
191+
192+
193+ tsp ([[1380 , 939 ], [2848 , 96 ], [3510 , 1671 ], [457 , 334 ], [3888 , 666 ], [984 , 965 ], [2721 , 1482 ], [1286 , 525 ],
194+ [2716 , 1432 ], [738 , 1325 ], [1251 , 1832 ], [2728 , 1698 ], [3815 , 169 ], [3683 , 1533 ], [1247 , 1945 ], [123 , 862 ],
195+ [1234 , 1946 ], [252 , 1240 ], [611 , 673 ], [2576 , 1676 ], [928 , 1700 ], [53 , 857 ], [1807 , 1711 ], [274 , 1420 ],
196+ [2574 , 946 ], [178 , 24 ], [2678 , 1825 ], [1795 , 962 ], [3384 , 1498 ], [3520 , 1079 ], [1256 , 61 ], [1424 , 1728 ],
197+ [3913 , 192 ], [3085 , 1528 ], [2573 , 1969 ], [463 , 1670 ], [3875 , 598 ], [298 , 1513 ], [3479 , 821 ], [2542 , 236 ],
198+ [3955 , 1743 ], [1323 , 280 ], [3447 , 1830 ], [2936 , 337 ], [1621 , 1830 ], [3373 , 1646 ], [1393 , 1368 ],
199+ [3874 , 1318 ], [938 , 955 ], [3022 , 474 ], [2482 , 1183 ], [3854 , 923 ], [376 , 825 ], [2519 , 135 ], [2945 , 1622 ],
200+ [953 , 268 ], [2628 , 1479 ], [2097 , 981 ], [890 , 1846 ], [2139 , 1806 ], [2421 , 1007 ], [2290 , 1810 ], [1115 , 1052 ],
201+ [2588 , 302 ], [327 , 265 ], [241 , 341 ], [1917 , 687 ], [2991 , 792 ], [2573 , 599 ], [19 , 674 ], [3911 , 1673 ],
202+ [872 , 1559 ], [2863 , 558 ], [929 , 1766 ], [839 , 620 ], [3893 , 102 ], [2178 , 1619 ], [3822 , 899 ], [378 , 1048 ],
203+ [1178 , 100 ], [2599 , 901 ], [3416 , 143 ], [2961 , 1605 ], [611 , 1384 ], [3113 , 885 ], [2597 , 1830 ], [2586 , 1286 ],
204+ [161 , 906 ], [1429 , 134 ], [742 , 1025 ], [1625 , 1651 ], [1187 , 706 ], [1787 , 1009 ], [22 , 987 ], [3640 , 43 ],
205+ [3756 , 882 ], [776 , 392 ], [1724 , 1642 ], [198 , 1810 ], [3950 , 1558 ]])
186206
207+ # tsp([[1, 1], [2, 5], [8, 0]])
187208
188- tsp ([[1 , 1 ], [2 , 5 ], [8 , 0 ]])
209+ #
210+ # tsp([
211+ # [0, 0],
212+ # [3, 0],
213+ # [6, 0],
214+ #
215+ # [0, 3],
216+ # [3, 3],
217+ # [6, 3],
218+ #
219+ # [0, 6],
220+ # [3, 6],
221+ # [6, 6],
222+ #
223+ # ])
0 commit comments