一、知识点回顾
(1)树:由 n 个结点,通过 n - 1条边相连且未构成回路的集合;
(2)生成树:给定一个无向图,如果它的某个子图中任意两个顶点都互相连通并且是一颗树。(生成树不唯一)
(3)最小生成树:如果边上有权值,那么使得权值和最小的生成树叫做最小生成树。
二、克鲁斯卡尔
(1)克鲁斯卡尔思想:
按照边的权值的顺序从小到大查看一遍,如果不产生环(重边也算在内),就把当前这条边加入到生成树中。
最后构成的生成树就是最小生成树;权值和最小。
(2)克鲁斯卡尔模板:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int per[110];//定义per数组,用来存放结点;
int n, m;
struct node {
int start;
int end;
int len;
}ans[10000];//结构体数组用来起点、终点、和权值;
int cmp(node a, node b){ //定义cmp函数,对权值升序排序;
return a.len < b.len;
}
void init(){
for(int i = 1; i <= n; ++i) //初始化
per[i] = i;
}
int find(int x){
if(x == per[x])
return x;
return per[x] = find(per[x]); //递归找根结点函数
}
bool join(int x, int y){
int fx = find(x);
int fy = find(y);
if(fx != fy){ //判断两点是否属于一个根结点,若是,返回假,不能相连
per[fx] = fy; //若否,返回真,将其相连;
return true;
}
return false;
}
int main (){
while(scanf("%d", &n), n){
m = n * (n - 1) / 2;
for(int i= 0; i < m; ++i)
scanf("%d%d%d", &ans[i].start, &ans[i].end, &ans[i].len);
sort(ans, ans + m, cmp);
int sum = 0;
init();
for(int i = 0; i < m; ++i){
if(join(ans[i].start, ans[i].end)) //为真,将其权值加到sum中;
sum += ans[i].len;
}
printf("%d\n", sum);
}
return 0;
}