最小全域木 クラスカル法
コンテンツ
UnionFindさえあれば,結構簡単に実装できるのね.
ただ,正しく動くかほとんど確認していないので,バグがあるかも.
// disjoint_set.h
#include <iostream>
using namespace std;
class UnionFind {
private:
int *root, *rank; // root < 0 のときはサイズの情報
public:
UnionFind(const int &n) {
root = new int[n], rank = new int[n];
fill_n(root, n, -1), fill_n(rank, n, 0);
}
int find(const int &x) {
if (root[x] < 0) return x;
return root[x] = find(root[x]);
}
void unionSet(const int &x, const int &y) {
int px = find(x), py = find(y);
if (px == py) return;
if (rank[px] > rank)
root[px] += root, root = px;
else if (rank[px] < rank)
root += root[px], root[px] = py;
else //if (rank[px] == rank)
root[px] += root, root = px, rank[px]++;
}
};
//kruskal.cpp
#include <queue>
#include "disjoint_set.h"
#include "graph.h"
template <class T>
EdgeList kruskal(const Graph &g, const EdgeProperty<T> &w) {
const int n = g.succ.size();
UnionFind u(n);
typedef pair<T, Edge> TE;
priority_queue<TE, vector<TE>, greater<TE> > q;
for (Vertex i = 0; i < n; ++i) foreach(Vertex j, g.succ[i])
if (i < j) q.push(TE(w(i, j), Edge(i, j)));
EdgeList t;
while (t.size() < n-1 && !q.empty()) {
const Edge e = q.top().second;
q.pop();
if (u.find(e.first) != u.find(e.second))
t.push_back(e), u.unionSet(e.first, e.second);
}
return t;
}
int main() {
const int n = 4;
Graph g(n);
EdgeProperty<int> w;
w[g.add_edge(0, 1)] = 3;
w[g.add_edge(1, 0)] = 3;
w[g.add_edge(0, 2)] = 2;
w[g.add_edge(2, 0)] = 2;
w[g.add_edge(1, 2)] = 1;
w[g.add_edge(2, 1)] = 1;
w[g.add_edge(0, 3)] = 0;
w[g.add_edge(3, 0)] = 0;
w[g.add_edge(3, 2)] = 1;
w[g.add_edge(2, 3)] = 1;
EdgeList mst = kruskal<int>(g, w);
foreach(Edge e, mst)
cout << e.first << " -> " << e.second << endl;
}
作成者 Toru Mano
最終更新時刻 2023-01-01 (c70d5a1)