Skip to content

Commit ced235e

Browse files
committed
Initial commit
0 parents  commit ced235e

1 file changed

Lines changed: 144 additions & 0 deletions

File tree

christofides.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
def tsp(data):
2+
length = 0
3+
visited = [False] * len(data)
4+
paths = []
5+
6+
G = build_graph(data)
7+
print("Graph: ", G)
8+
9+
MSTree = minimum_spanning_tree(G)
10+
print("MSTree: ", MSTree)
11+
12+
# find odd vertexes
13+
odd_vertexes = find_odd_vertexes(MSTree)
14+
print("Odd vertexes in MSTree: ", odd_vertexes)
15+
16+
# add minimum weight matching edges to MST
17+
minimum_weight_matching(MSTree, G, odd_vertexes)
18+
print("Minimum weight matching: ", MSTree)
19+
20+
21+
def get_length(x1, y1, x2, y2):
22+
return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** (1 / 2)
23+
24+
25+
def build_graph(data):
26+
graph = {}
27+
for this in range(len(data)):
28+
for another_point in range(len(data)):
29+
if this != another_point:
30+
if this not in graph:
31+
graph[this] = {}
32+
33+
graph[this][another_point] = get_length(data[this][0], data[this][1], data[another_point][0],
34+
data[another_point][1])
35+
36+
return graph
37+
38+
39+
class UnionFind:
40+
"""Union-find data structure.
41+
42+
Each unionFind instance X maintains a family of disjoint sets of
43+
hashable objects, supporting the following two methods:
44+
45+
- X[item] returns a name for the set containing the given item.
46+
Each set is named by an arbitrarily-chosen one of its members; as
47+
long as the set remains unchanged it will keep the same name. If
48+
the item is not yet part of a set in X, a new singleton set is
49+
created for it.
50+
51+
- X.union(item1, item2, ...) merges the sets containing each item
52+
into a single larger set. If any item is not yet part of a set
53+
in X, it is added to X as one of the members of the merged set.
54+
"""
55+
56+
def __init__(self):
57+
"""Create a new empty union-find structure."""
58+
self.weights = {}
59+
self.parents = {}
60+
61+
def __getitem__(self, object):
62+
"""Find and return the name of the set containing the object."""
63+
64+
# check for previously unknown object
65+
if object not in self.parents:
66+
self.parents[object] = object
67+
self.weights[object] = 1
68+
return object
69+
70+
# find path of objects leading to the root
71+
path = [object]
72+
root = self.parents[object]
73+
while root != path[-1]:
74+
path.append(root)
75+
root = self.parents[root]
76+
77+
# compress the path and return
78+
for ancestor in path:
79+
self.parents[ancestor] = root
80+
return root
81+
82+
def __iter__(self):
83+
"""Iterate through all items ever found or unioned by this structure."""
84+
return iter(self.parents)
85+
86+
def union(self, *objects):
87+
"""Find the sets containing the objects and merge them all."""
88+
roots = [self[x] for x in objects]
89+
heaviest = max([(self.weights[r], r) for r in roots])[1]
90+
for r in roots:
91+
if r != heaviest:
92+
self.weights[heaviest] += self.weights[r]
93+
self.parents[r] = heaviest
94+
95+
96+
def minimum_spanning_tree(G):
97+
tree = []
98+
subtrees = UnionFind()
99+
for W, u, v in sorted((G[u][v], u, v) for u in G for v in G[u]):
100+
if subtrees[u] != subtrees[v]:
101+
tree.append((u, v, W))
102+
subtrees.union(u, v)
103+
104+
return tree
105+
106+
107+
def find_odd_vertexes(MST):
108+
tmp_g = {}
109+
vertexes = []
110+
for edge in MST:
111+
if edge[0] not in tmp_g:
112+
tmp_g[edge[0]] = 0
113+
114+
if edge[1] not in tmp_g:
115+
tmp_g[edge[1]] = 0
116+
117+
tmp_g[edge[0]] += 1
118+
tmp_g[edge[1]] += 1
119+
120+
for vertex in tmp_g:
121+
if tmp_g[vertex] % 2 == 1:
122+
vertexes.append(vertex)
123+
124+
return vertexes
125+
126+
127+
# utility function that adds minimum weight matching edges to MST
128+
def minimum_weight_matching(MST, G, odd_vert):
129+
while odd_vert:
130+
v = odd_vert.pop()
131+
length = float("inf")
132+
u = 1
133+
closest = 0
134+
for u in odd_vert:
135+
if G[v][u] < length:
136+
length = G[v][u]
137+
closest = u
138+
139+
MST.append((v, closest, length))
140+
odd_vert.remove(closest)
141+
142+
143+
144+
tsp([[1, 1], [2, 5], [8, 0]])

0 commit comments

Comments
 (0)