图论-kruscal

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值