最小生成树浅谈(1)

最小生成树

概念:将给出的所有点连接起来(即从一个点可到任意一个点),且连接路径之和最小的图叫最小生成树。

数据结构:树形结构,或者说是直链型结构,因为当n个点相连,且路径和最短,那么将它们相连的路一定是n-1条

实现思路:将点分为在树中的点与不在树中的点,每次取出树中点的连接的最小路径,且该路径连接的点不在树中,然后将该路径连接的点加入树中,重复并进行路径更新,即松弛,当取出边达到n-1条时,树已建立。

难点:

1.如何找最小边

2.如何判断点在一个树

方法:

1.实现思路的再创新:在树中找最小边,不如直接将所有边存起来,进行遍历,看看这条边适不适合用来连接,此时会出现多个树的生成,但是没关系,最后还是会连接到一起的

2.当用一的方法实现了后,只需要进行每条边连接的两点是否在一树中的判断了,在一个树中,不用再连接了,因为前面比较小的边已经将他们连起来了,所以只需要用并查集进行两点是否同源的判断了

以下是代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define re register
#define MANN 250000
#define MANX 6000
using namespace std;
struct edge{
    int u,v,w;
}e[MANN];
int n,m,x,y,t,f[MANX],Count,sum,p;
bool cmp(edge a,edge b){
    return a.w<b.w;
}
int getf(int k){//并查集压缩
    if(f[k]==k) return k;
    return f[k]=getf(f[k]);
}
int qmerge(int a,int b){//进行合并同时判断是否同源
    int t1,t2;
    t1=getf(a);
    t2=getf(b);
    if(t1!=t2){
        f[t1]=t2;
        return 1;
    }
    return 0;
}
int main(){
    cin>>n>>m;
    for(re int i=1;i<=n;i++)f[i]=i;
    
    for(re int i=1;i<=m;i++){
        scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    }
    
    sort(e+1,e+m+1,cmp);
    
    for(re int i=1;i<=m;i++){
        
        if(qmerge(e[i].u,e[i].v)){
            Count++;
            sum+=e[i].w;
        }
        if(Count==n-1)break;
    }
    if(Count!=n-1)cout<<"不能生成最小生成树"<<endl;
    else 
    cout<<sum<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/dancemu/p/10789726.html