最小生成樹淺談(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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM