Przejdź do treści

Kruskal

Opis problemu

Implementacja

import heapq

class DisjointUnion:
    class Node:
        def __init__(self, parent: int, rank: int):
            self.parent = parent
            self.rank = rank

    def __init__(self, number_of_nodes: int):
        self._subsets = [self.Node(i, 0) for i in range(number_of_nodes)]

    def union(self, el1: int, el2: int):
        x_root = self.find(el1)
        y_root = self.find(el2)

        if self._subsets[x_root].rank < self._subsets[y_root].rank:
            self._subsets[x_root].parent = y_root
        elif self._subsets[x_root].rank > self._subsets[y_root].rank:
            self._subsets[y_root].parent = x_root
        else:
            self._subsets[y_root].parent = x_root
            self._subsets[x_root].rank += 1

    def is_in_union(self, el1: int, el2: int) -> bool:
        return self.find(el1) == self.find(el2)

    def find(self, node_number: int) -> int:
        if self._subsets[node_number].parent != node_number:
            self._subsets[node_number].parent = self.find(self._subsets[node_number].parent)

        return self._subsets[node_number].parent

class Edge:

  def __init__(self, node_from: int, node_to: int, distance: int):
    self.node_from = node_from
    self.node_to = node_to
    self.distance = distance

  def __lt__(self, other) -> bool:
    return self.distance < other.distance

  def __str__(self) -> str:
    return f"{self.node_from} <-({self.distance})-> {self.node_to}"

  def __repr__(self) -> str:
    return self.__str__()

def kruskal(graph: list) -> list:
  edges = []
  connected_nodes = DisjointUnion(len(graph))

  min_spanning_tree = []

  for nodes_list in graph:
    for node in nodes_list:
      edges.append(node)

  heapq.heapify(edges)
  while edges:
    current = heapq.heappop(edges)

    if connected_nodes.is_in_union(current.node_from, current.node_to):
      continue

    connected_nodes.union(current.node_from, current.node_to)
    min_spanning_tree.append(current)

  return min_spanning_tree

if __name__ == "__main__":
  graph = [[Edge(0, 1, 5), Edge(0, 6, 5)],
           [Edge(1, 0, 5),
            Edge(1, 6, 5),
            Edge(1, 3, 3),
            Edge(1, 2, 3)], [Edge(2, 1, 3), Edge(2, 3, 1)],
           [
             Edge(3, 2, 1),
             Edge(3, 1, 3),
             Edge(3, 6, 3),
             Edge(3, 4, 5),
             Edge(3, 5, 4)
           ], [Edge(4, 3, 5), Edge(4, 5, 2)],
           [Edge(5, 4, 2), Edge(5, 3, 4),
            Edge(5, 6, 5)],
           [Edge(6, 0, 5),
            Edge(6, 1, 5),
            Edge(6, 3, 3),
            Edge(6, 5, 5)]]

  min_spanning_tree = kruskal(graph)

  print(min_spanning_tree)