$\newcommand{\O}{\mathrm{O}}$

グラフの最小全域木の重みを求めるアルゴリズム.
最小全域木とはもとのグラフの部分グラフでありかつすべての頂点を含む木のなかで辺の重みの総和が最小のもののことである. 同じく最小全域木を求めるアルゴリズムとして Prim 法 がある.
コストの小さい辺から(閉路ができないように)貪欲に取っていくことでアルゴリズムが正しく動くことが知られている. 証明はグラフ, マトロイドの両面から示せる.
グラフの側面から示した証明はよくあるので, マトロイドの側面から Kruskal 法の正当性を示してみた(⇒ 補足).
(関数)
add_edge$(u, v, cost)$ : $u$, $v$ の間に重み $cost$ の無向辺を追加する
solve(): 最小全域木の重みを計算する
時間計算量: $\O (m \log n)$
class UnionFind:
def __init__(self, node_size):
self._node = node_size
self.par = [i for i in range(self._node)]
self.rank = [0] * self._node
def find(self, ver):
if self.par[ver] == ver:
return ver
else:
self.par[ver] = self.find(self.par[ver])
return self.par[ver]
def unite(self, ver1, ver2):
ver1, ver2 = self.find(ver1), self.find(ver2)
if ver1 == ver2:
return
if self.rank[ver1] < self.rank[ver2]:
ver1, ver2 = ver2, ver1
self.par[ver2] = ver1
if self.rank[ver1] == self.rank[ver2]:
self.rank[ver1] += 1
def same(self, ver1, ver2):
return self.find(ver1) == self.find(ver2)
class Kruskal:
class Edge:
def __init__(self, u, v, cost):
self.u, self.v, self.cost = u, v, cost
def __lt__(self, another):
return self.cost < another.cost
def __init__(self, node_size):
self._node = node_size
self._edge_list = []
def add_edge(self, u, v, cost):
self._edge_list.append(self.Edge(u, v, cost))
def solve(self):
uf = UnionFind(self._node)
res = 0
edge_count = 0
self._edge_list.sort()
for e in self._edge_list:
if not uf.same(e.u, e.v):
uf.unite(e.u, e.v)
res += e.cost
edge_count += 1
if edge_count == self._node-1:
break
return res
AOJ : Minimum Spanning Tree 提出コード