最小生成树
克鲁斯卡尔算法
适合于求边稀疏的网的最小生成树
思路:
将每条边的权值按从小到大的顺序排列,然后遍历,将边放回图中,如果此时的连线不能形成环,则继续,否则将此边丢弃,直到放进去n-1条边(n个点连通需要n-1条边)结束
用结构体存储顶点和边,sort排序
struct bian//存储边的信息 { int x,y,w; }a[maxn];
如何判断是否成环----并查集(https:////www.cnblogs.com/subject/p/12386581.html)
如果最终父类相同说明在一个集合中(形成环)
int getfather(int x)//递归找父类 { if(father[x]==x) return x; father[x] = getfather(father[x]); return father[x]; } void unionm(int x,int y)//合并 { int fa,fb; fa = getfather(x); fb = getfather(y); if(fa!=fb) father[fa] = fb; } void Init()//父类初始化 { for(int i = 1;i <= n;i++) father[i] = i; return; }; void Kruskal() { int ans = 0;//记录权值 int k = 0;//记录已经连几条边 for(int i=1;i<=m;i++) { if(getfather(a[i].x)!=getfather(a[i].y))//父类不同,说明是两个集合,此边可取 { unionm(a[i].x,a[i].y);//合并为一个集合 ans+=a[i].w;//权值相加 k++; } if(k==n-1) break; } if(k==n-1) cout<<ans<<endl; else cout<<"impossible"<<endl;//遍历完 也不够n-1条 说明不能形成通路。 }
完整代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e5+5; struct bian//存储边的信息 { int x,y,w; }a[maxn]; int father[maxn];//每个点的最终父类 int n,m; bool cmp(const bian& a,const bian& b) { return a.w<b.w; } int getfather(int x)//递归找父类 { if(father[x]==x) return x; father[x] = getfather(father[x]); return father[x]; } void unionm(int x,int y)//合并 { int fa,fb; fa = getfather(x); fb = getfather(y); if(fa!=fb) father[fa] = fb; } void Init()//父类初始化 { for(int i = 1;i <= n;i++) father[i] = i; return; }; void Kruskal() { int ans = 0; int k = 0; for(int i=1;i<=m;i++) { if(getfather(a[i].x)!=getfather(a[i].y)) { unionm(a[i].x,a[i].y); ans+=a[i].w; k++; } if(k==n-1) break; } if(k==n-1) cout<<ans<<endl; else cout<<"impossible"<<endl; } int main() { cin>>n>>m; for(int i=1;i<=m;i++) { cin>>a[i].x>>a[i].y>>a[i].w; } Init(); sort(a+1,a+1+m,cmp); Kruskal(); return 0; }