- 算法思想
1.令初始状态有n个顶点而无边的非连通图 ,图中每个顶点自成一个连通分量。
2.在边集表中选择代价最小的边。
3.用Find函数(代码中有注释)查找若该边依附的顶点,若落在中不同的连通图上,则将此边相连,合成一个新的连通图,否则舍去此边。
重复2,3操作,直到把所有的点连到一起为止
值得注意的是,构成最小生成树的边是n-1个,因此,可以对添边操作进行计数,循环n-1次即可停止循环。
- 图示
补充说明
1.初始化图中六个小镇为独立的六个连通分量。
2.依次连接权制为3,4,4的边
3.直到找到权制为5的边时,发现此边的两个顶点庆卫镇,高山镇来自同一个连通图,舍去此边,找到下一条边,并对其进行判断。
4.直到添加了n-1条边为止
输入
第一行顶点个数你,边数m。
接下来的m行分别输入m条边的信息:对应的两个顶点的序号和权值(在这里顶点名为数字,当然也可以用字符使用strcmp函数)
#include<cstdio>
#include<iostream>
using namespace std;
const int M=20000;
int F[M];
int n,m;
struct Edge{//
int u,v,w;
}edges[200000];
bool cmp(Edge a,Edge b){
return a.w<b.w;
}
int Find(int x)
{
if(F[x]==-1){
return x;
}else{
return F[x]=Find(F[x]);//有一点回溯算法的意思,找到此连通图最原始的顶点。
}
}
int kruskal(int n){
sort(edges,edges+m, cmp);
int cnt=0;
int ans=0;
for(int i=0;i<m;i++){
int u=edges[i].u;
int v=edges[i].v;
int w=edges[i].w;
int t1=Find(u);
int t2=Find(v);
if(t1!=t2){//如果两个点分别来自不同的连通图
ans+=w;
F[t1]=t2;//t1点与t2点相连
cnt++;
}
if(cnt==n-1){
break;
}
}
if(cnt<n-1){
return -1;
}else{
return ans;
}
}
int main()
{
memset(F, -1, sizeof(F));//初始化:每个顶点都不与其他顶点相连
cin>>n>>m;
for(int i=0;i<m;i++){
int a,b,w;
cin>>a>>b>>w;
edges[i]={a,b,w};
}
cout<<kruskal(n)<<endl;
return 0;
}
结果: