summaryrefslogtreecommitdiffstats
path: root/heuristics/Christofides.py
blob: b3316e8d9d2565f5991cdd53f21acdac09a1f83f (plain)
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
from graph import distance, find_MST, calculate_route
from queue import Queue
from collections import Counter
from copy import deepcopy

def linker2(points):
    route = []
    graph = dict()

    for pair in points:
        start, end = pair
        if start in graph:
            graph[start].append(end)
        else:
            graph[start] = [end]

        if end in graph:
            graph[end].append(start)
        else:
            graph[end] = [start]
    q = Queue()
    q.put(([points[0][0]], points[:]))
    seen = set()
    while not q.empty():
        current, pts = q.get()

        if tuple(current) in seen:
            continue
        else:
            seen.add(tuple(current))

        if len(pts) == 0:
            s = set()
            for i in current:
                if i not in s:
                    route.append(i)
                    s.add(i)
            break

        for i in graph[current[-1]]:
            if (current[-1], i) in pts:
                temp = deepcopy(current)
                temp.append(i)
                temp2 = pts[:]
                temp2.remove((current[-1], i))
                q.put((temp,temp2))
            elif (i,current[-1]) in pts:
                temp = deepcopy(current)
                temp.append(i)
                temp2 = pts[:]
                temp2.remove((i,current[-1]))
                q.put((temp,temp2))

    return route

def christofides(graph: list):
    _, mst = find_MST(graph)
    g = {town: [] for town in graph}
    for i in mst:
        start, end = i
        g[start].append(end)
        g[end].append(start)

    odd_degree_vertices = []

    for town in g:
        degree = len(g[town])
        if degree % 2 == 1:
            odd_degree_vertices.append(town)

    def is_seen(points, value):
        for i in points:
            s, e = i
            if value == s or value == e:
                return True
        return False

    perfect_matching = []
    q = Queue()
    q.put([])

    min_weight = None
    while not q.empty():
        current = q.get()
        if len(current) == len(odd_degree_vertices) / 2:
            d = calculate_route(current, "points")
            if min_weight is None or d < min_weight:
                min_weight = d
                perfect_matching = current

        for i in odd_degree_vertices:
            if not is_seen(current, i):
                for j in odd_degree_vertices:
                    if j != i and not is_seen(current,j):
                        c = current[:]
                        c.append((i, j))
                        q.put(c)


    multigraph = mst + perfect_matching
    # print(f"{odd_degree_vertices=}")
    # print(f"{mst=}")
    # print(f"{perfect_matching=}")
    # print(f"{multigraph=}")

    eulerian_tour = linker2(multigraph)
    #
    #
    # print(g)
    return eulerian_tour

"""


((396, 559), (300, 438)), 1
((300, 438), (141, 520)), 2
((300, 438), (490, 227)), 
((300, 438), (24, 97)), 
((396, 559), (141, 520)), 3
((24, 97), (490, 227))"""