最小生成树
概念:将给出的所有点连接起来(即从一个点可到任意一个点),且连接路径之和最小的图叫最小生成树。
数据结构:树形结构,或者说是直链型结构,因为当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; }