首先明确以下概念:
(1)连通图:无向图都有任意两个节点都能有路径相通。
(2)强连通图:有向图中任意两个节点都有路径相通。
(3)连通网:连通图中的边有权。
(4)生成树:一个连通图的生成树是指一个连通子图,含有图中全部n个顶点,仅有n-1条边,如果再添加一条边就必定成环。
(5)最小生成树:连通网中所有生成树中权值和最小的生成树。
Kruskal算法:
定义一个概念——安全边:正确的边是安全边,边的两个端点处在两个集合内的边是正确的边,就是把新的点加入到原本的集合内。
将所有的边存入并排序,每次取得权值最小的加入到sum中,每次取边之前先判断这条边的两个端点是否都在同一集合内,如果在说明已经加入过就不选这个,如果不在就要选他,选了之后要把新的点加入到集合内。执行上述操作直到遍历所有的边。
每一条边都存入一个结构体数组中。
struct edge{
int bgn;
int nd;
int len;
}e[1005];
对于判断是否属于同一集合的方式我们采用“并查集”。
void init(int n){
for(int i = 0; i <= n; i++)
ar[i] = i;
}
int find_boss(int x){
if(x != ar[x])
ar[x] = find_boss(ar[x]);
return ar[x];
}
bool same(int x, int y){
return find_boss(x) == find_boss(y);
}
void unite(int x, int y){
int i = find_boss(x);
int j = find_boss(y);
ar[j] = i;
}
完整代码如下:
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
struct edge{
int bgn;
int nd;
int len;
}e[10005];
int ar[10005];
int sum;
bool cmp(edge a, edge b){
return a.len < b.len;
}
void init(int n){
for(int i = 0; i <= n; i++){
ar[i] = i;
}
memset(e, 0, sizeof(e));
sum = 0;
}
int find_boss(int x){
if(x != ar[x]){
ar[x] = find_boss(ar[x]);
}
return ar[x];
}
bool same(int x, int y){
return find_boss(x) == find_boss(y);
}
void unite(int x, int y){
ar[find_boss(x)] = find_boss(y);
}
int main(){
int poi_n, len_n;
cin >> poi_n >> len_n;
init(len_n);
for(int i = 0; i < len_n; i++){
cin >> e[i].bgn >> e[i].nd >> e[i].len;
}
sort(e, e + len_n, cmp);
for(int i = 0; i < len_n; i++){
if(!same(e[i].bgn, e[i].nd)){
sum += e[i].len;
unite(e[i].bgn, e[i].nd);
}
}
cout << sum << endl;
return 0;
}