最小生成树kruskal求法:对边权排序之后,用并查集去链接集合,直到剩下一个集合结束 kruskal算法: //第一步:给所有边按照从小到大的顺序排列 //知识点:联通分量的概念: //(1)在无向图中,如果顶点Vi到顶点Vj有路径,则称顶点Vi和Vj联通 //(2)如果无向图中任意两个顶点之间都连通,则称为连通图 //(3)如果不是连通图,则图中的 极大连通子图 称为连通分量 接下来要从小到大依次考察每条边(u,v) //(1)u和v在同一个连通分量中,那么加入(u,v)后会形成环,因此不能选择 //(2)如果在不同的连通分量里面,那么加入后一定是最优的 //一开始要初始化连通分量,让每个点都自成一个独立的连通分量 例题:洛谷:P3366:https://www.luogu.com.cn/problem/P3366 #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <iostream> #include <algorithm> #include <vector> #include <stack> #include <sstream> #include <map> #include <set> #include <queue> #include <stdlib.h> typedef long long ll; using namespace std; struct edge { ll u,v,w; }e[200010]; bool cmp(edge &a,edge &b) { return a.w<b.w; } ll f[200005],n,m,ans,cnt; ll find(ll x) { if(f[x]!=x) f[x]=find(f[x]); return f[x]; } void kruskal() { sort(e,e+m,cmp); for(int i=0;i<m;i++) { ll u=e[i].u; ll v=e[i].v; ll w=e[i].w; ll fu=find(u), fv=find(v); if(fu==fv) continue; //如果两者在一个连通图里面,continue ans+=w; f[fv]=fu;//一定是将两者的祖先连在一起 cnt++; if(cnt==n-1) break; //最小生成树只有n-1条边 } } int main() { cin >> n >> m; for(int i=1;i<=n;i++) { f[i]=i; } //每个点都自成一个连通量 for(int i=0;i<m;i++) { cin >> e[i].u >> e[i].v >> e[i].w; //输入两个端点和边的权值 } kruskal(); if(cnt!=n-1) { printf("orz"); } printf("%lld",ans); return 0; }