最小生成树(并查集)

最小生成树

最小生成树(Minimum Spanning Tree)问题是图论中的一个经典问题,它的目标是在一个连通加权无向图中找到一棵边权值和最小的生成树。解决最小生成树问题的算法常见的有Kruskal算法和Prim算法。

Kruskal算法

假设连通网G=(V,E),令最小生成树的初始状态为只有n个顶点而无边的非连通图,概述图中每个顶点自成一个连通分量。在E中选择代价最小的边,若该边依附的顶点分别在T中不同的连通分量上,则将此边加入到T中;否则,舍去此边而选择下一条代价最小的边。依此类推,直至T中所有顶点构成一个连通分量为止。

具体实现

实现Kruskal算法的最主要两个核心:一个是找到最小的边和判断两个节点是否在同一个连通分量上。

每次找最小的边,实际上就是对输入的边进行排序(如果是prim算法则使用优先队列),这样就可以得到边从小到大的集合:

struct w{
    int x,y,l;
};//定义边结构体

bool cmp(w &m1,w &m2){
    return m1.l<m2.l;
}//自定义边的比较方式

w v[80];//边集

sort(v,v+len,cmp);//排序
        

判断是否在同一个连通分量上可以使用并查集算法

int count=0;
int sum=0;
sort(v,v+p,cmp);
for(int i=0;i<p;i++){
   if(Find(v[i].x)!=Find(v[i].y)){//如果不在同一连通分量,则将边加入
     f[Find(v[i].x)]=Find(v[i].y);//连接两个点的连通分量
     sum+=v[i].l;
     count++;
     }
   if(count==n-1) break;//对于n点的图,最小生成树有n-1条边,程序可以提前退出
}

完整代码:

#include<cstdio>
#include<algorithm>
using namespace std;
struct w{
    int x,y,l;
};

bool cmp(w &m1,w &m2){
    return m1.l<m2.l;
}

w v[80];
int f[30];
void init(int n){
    for(int i=0;i<=n;i++){
        f[i]=i;
    }
}

int Find(int x){
    while(x!=f[x]){
        x=f[x]=f[f[x]];
    }
    return x;
}
int main(){
    int n;
    while(scanf("%d",&n)&&n!=0){
        init(n);
        char s,t;
        int a,b,c;
        int p=0;
        for(int i=0;i<n-1;i++){//输入边集
            cin>>s>>a;
            b=s-'A'+1;
            for(int j=0;j<a;j++){
                cin>>t>>c;
                v[p].x=b;
                v[p].y=t-'A'+1;
                v[p].l=c;
                p++;
            }
        }
        int count=0;
        int sum=0;
        sort(v,v+p,cmp);
        for(int i=0;i<p;i++){
            if(Find(v[i].x)!=Find(v[i].y)){
                f[Find(v[i].x)]=Find(v[i].y);
                sum+=v[i].l;
                count++;
            }
            if(count==n-1) break;
        }
        printf("%d\n",sum);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值