Kruskal算法:
①用并查集实现
②构造一个只含 n 个顶点,边集为空的子图,把子图中各个顶点看成各棵树上的根结点
③sort()排序升序,依次从边集 E 中选取一条权值最小的边,如果该条边的两个顶点分属不同的树,则把两棵树合成一棵树。若该条边的两个顶点已落在同一棵树上,跳过,取下一条权值最小的边再试之。子图中含有 n-1 条边就结束,此时森林中只有一棵树
注意:顶点个数的最大值和边的个数的最大值是不一样的,要单独定义一个MAX_EDG
#include <stdio.h> #include <algorithm> #define MAX 100 #define MAX_EDG 1000 using namespace std; typedef struct Node{ int u; int v; int w; }Node; Node map[MAX_EDG]; //注意:顶点数和边数的最大值是不一样的,要分别定义 int father[MAX]; //自己的父亲 int rank_[MAX]; //秩 bool cmp(Node a, Node b){ return a.w < b.w; //从小到大 升序 } int find(int x){ if(father[x]==x) return x; else return father[x]=find(father[x]); //向上找父亲直到找到根节点 } void unite(int x, int y){ if(find(x) == find(y)) return; else{ int x_root=find(x); int y_root=find(y); if(rank_[x_root] > rank_[y_root]) //按秩合并 //比较的是树根x_root和y_root的秩 ,不是x和y的 father[y_root]=x_root; else if(rank_[y_root] > rank_[x_root]) father[x_root]=y_root; else{ //两个树根的秩一样的话,任意合并到其中一个树根中,然后秩++ father[x_root]=y_root; rank_[y_root]++; } } } void init(int n){ for(int i=1;i<=n;i++){ father[i]=i; //自己是自己的父亲 rank_[i]=0; //初始高度为0 } } int main(){ int n,m; int count,sum; int u,v,w; while(scanf("%d %d",&n,&m)!=EOF){ init(n); for(int i=1;i<=m;i++) scanf("%d %d %d",&map[i].u,&map[i].v,&map[i].w); sort(map+1, map+m+1, cmp); //sort排序,由小到大 count=0; sum=0; for(int i=1;i<=m;i++){ if(count==n-1) break; //n个顶点被n-1条边连接就跳出 u=map[i].u; v=map[i].v; w=map[i].w; if(find(u)!=find(v)){ //如果不在同一个子树就合并 unite(u,v); count++; sum+=w; } } printf("%d\n",sum); //sum是n-1条边的边权和 } return 0; }
原文:https://www.cnblogs.com/shiliuxinya/p/12194545.html