Kruscal算法
每个顶点一棵树,并将边按权重升序排列。然后从前到后按循序选边,如果当前选择的边的两个顶点分在两棵不同的树中,则将该边加入到最小生成树中,并合当前边连接的两棵树,如果边的两个顶点在相同的树中,则不做任何处理。
跟着思路java敲了一遍
//排序调用该方法比较图中边的大小
static boolean cmp(edge a, edge b){
return a.w < b.w;
}
//寻找根节点,判断是否在同一棵树中的依据
static int Find(G g,int x){
if(g.parent[x] == -1) return x;
return Find(g,g.parent[x]);
}
//排序方法,对EG数组(存放所有边的数组)按权值大小进行排序
static void sortEG(G g) {
for(int i=0; i<g.arcnum-1; i++){
int minIndex = i;
for(int j=minIndex+1;j<g.arcnum;j++){
if(cmp(g.EG[j],g.EG[minIndex])){
minIndex = j;
}
}
edge temp = g.EG[i]; //交换
g.EG[i] = g.EG[minIndex];
g.EG[minIndex] = temp;
}
}
//Kruskal算法,parent能够还原一棵生成树,或者森林
static int Kruskal(G g){
int ans=0; //存放最小生成树权值
g.prev = new int[g.MAX_N]; //存储先驱结点
g.dist = new int[g.MAX_N]; //存储结点之间的距离
g.parent = new int[g.MAX_N]; //父亲节点,当值为-1时表示根节点
g.visit = new int[g.MAX_N]; //记录结点是否被访问过
sortEG(g); //按权值将边从小到大排序
for(int k=0;k<g.vernum;k++) { //初始化并查集森林
g.parent[k] = -1;
}
ans = 0;
for(int i = 0; i < g.arcnum; i++){ //按权值从小到大选择边
int t1 = Find(g,g.EG[i].u), t2 = Find(g,g.EG[i].v);
if(t1 != t2){ //若不在同一棵树种则选择该边,合并两棵树
ans += g.EG[i].w;
g.parent[t1] = t2;
}
}
return ans;
}
//打印并查集结果
static void print_EG(G g) {
for(int i=0;i<g.arcnum;i++) { //第一行打印索引值
System.out.printf("%2s",i+"\t");
}
System.out.println();
for(int j=0;j<g.parent.length;j++) { //第二行打印并查集数组
System.out.printf("%2s",g.parent[j]+"\t");
}
System.out.println();
}
大神C++模板,思路清晰
https://www.cnblogs.com/XjzLing/p/7943259.html
#include<algorithm>
#include<iostream>
#include<cstdio>
#define maxn 200000 + 10
using namespace std;
int n,m,ans,num;
int fa[maxn];
struct edge{
int frm,to,val;
}G[maxn];
//记录边的信息:起点,终点,权
void init(){
for(int i=1;i<=n;i++) fa[i]=i;
}//并查集预处理
bool cmp(edge a,edge b){
return a.val<b.val;
}// 用于sort的cmp函数
int find(int x){
if(x==fa[x]) return x;
else return fa[x]=find(fa[x]);
}//并查集找祖先
bool merge(edge a){
if(find(a.frm)!=find(a.to)){
fa[fa[a.to]]=find(a.frm);
return true;
}
return false;
}//并查集连边
int main(){
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=m;i++) scanf("%d%d%d",&G[i].frm,&G[i].to,&G[i].val);
sort(G,G+m,cmp);//将边权从小到大排序
for(int i=1;i<=m && num<n-1;i++)
if(merge(G[i])){
ans+=G[i].val;
num++;
}//Kruscal操作
if(num==n-1) printf("%d",ans);
else printf("orz");
return 0;
}