1.基本的な考え方
n個のノードとm個のエッジがあると仮定すると、重みが最小のエッジが、選択されていないエッジセットEから毎回選択されます。最小のエッジの端が、選択されたエッジの端とループを形成しない場合、エッジが最小スパニングツリーに追加されます。n-1個のエッジが選択されるか、エッジが選択されなくなるまで、この手順を繰り返します。例は次のとおりです。図
には9つのエッジが
あり、最初は最小のエッジが選択され、重みは1で、ノードv1とv3にラベルが付けられています。
2回目:重みが2の最小のエッジを選択すると、ノードv1とv4にラベルが付けられます。
3回目:最小のエッジが選択され、重みは3で、ノードv1とv5にラベルが付けられます。
4回目:最小のエッジが選択され、重みは3で、ノードv2とv4にラベルが付けられます。
選択したエッジはn-1に到達し、終了します。
2,注意点
ここでの主な注意点は、選択の過程で2つのポイントがループを構成しているかどうかを判断する方法です。他の著者の判断方法を読んだ後、考え方はほぼ同じです(最初はいつも理解していませんでしたが、私は最終的にそれを理解したか、それは私がそれを行うのが面倒だったためでした。この例はもう一度やり直します)、これは2つのポイントの親ノード(ここでは親ノードが正確ではなく、大まかな意味)であるかどうかを判断することです)は同じです。同じ場合はループを形成し、エッジは望ましくありません。異なる場合はエッジが望ましいです。
3.コードの実装
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct edge
{
int u, v;
int weight;
};
vector<int> father; //记录每个节点的父亲
vector<int> result; //存储最后获得的各条边
bool compare(edge a, edge b)
{
return a.weight < b.weight;
}
int findfather(int a)
{
while (a != father[a])
{
a = father[a];
}
return a;
}
void kruskal(int n, vector<edge> Edge)
{
father.resize(n);
sort(Edge.begin(), Edge.end(), compare);
for (int i = 0; i < n; ++i)
{
father[i] = i;
}
for (int i = 0; i < Edge.size() && result.size() < n-1; ++i)
{
int u = Edge[i].u;
int v = Edge[i].v;
if (findfather(u) != findfather(v)) //判断父节点是否相同
{
result.push_back(Edge[i].weight);
father[findfather(u)] = father[findfather(v)]; //将两点并入一个集合中
}
}
if (result.size() != n - 1)
{
cout << result.size() << "该图不连通" << endl;
return;
}
else
{
cout << "最小生成树的各边如下:" << endl;
for (int i = 0; i < result.size(); ++i)
{
cout << result[i] << endl;
}
}
}
int main()
{
int n, m;
cout << "输入结点数:";
cin >> n;
cout << "输入边数:";
cin >> m;
vector<edge> Edge(m);
cout << "输入各条边的信息:" << endl;
for (int i = 0; i < m; ++i)
{
cin >> Edge[i].u >> Edge[i].v >> Edge[i].weight;
}
kruskal(n,Edge);
return 0;
}
入力および出力情報: