最小生成樹
概念:將給出的所有點連接起來(即從一個點可到任意一個點),且連接路徑之和最小的圖叫最小生成樹。
數據結構:樹形結構,或者說是直鏈型結構,因為當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; }