图论:Kruskal算法 求最小生成树
Kruskal算法 求最小生成树
先构建邻接关系的结构体
struct edge
{
int u,v,w;
}e[maxn];
因为这个算法利用到了并查集,所以需要构建并查集数组parent[],并且初始化并查集数组parent
int parent[maxn];//并查集
for(int i=1;i<=n;++i)
{
parent[i]=i;//初始化并查集
}
然后就是很重要的一步,对邻接关系进行排序,注意初始化邻接关系时,虽然是无向图,但是只要记录起点和终点就行,不需要双向的,因为这里最重要的是权值。排序用的是权值进行排序。
初始化邻接关系:
for(int i=1;i<=m;++i)
{
cin>>a>>b>>c;
e[i].u=a,e[i].v=b,e[i].w=c;
}//初始化边
排序就需要定义一个排序规则,注意是从小到大
排序规则:
bool cmp(const edge&a,const edge&b)
{
return a.w<b.w;
}
然后排序:
sort(e+1,e+1+n,cmp);//快排
排序以后,就是处理每一个邻接关系,遍历每一个邻接关系,如果起点和终点不是同属一个集合,那么就把它们的边权加入mst,并且合并这两个点所在的集合,如果是同一个集合,就跳过,注意这里要定义一个k,记录加入几条边了,每次加入一次mst就++k一次,如果k==n-1,那么就break,退出循环,因为最小生成树中只能有n-1条边。 这里就需要并查集寻找所在集合,和合并集合的函数。
寻找所在集合函数
find:
int find(int x)//查找根节点并且压缩路径
{
if(parent[x]!=x)
parent[x]=find(parent[x]);
return parent[x];
}
合并集合函数:
unions:
void unions(int x,int y)//合并两个集合
{
parent[find(y)]=find(x);
}
处理每一个邻接关系:
for(int i=1;i<=m;++i)
{
if(find(e[i].u)!=find(e[i].v))
{
++k;
mst+=e[i].w;
unions(e[i].u,e[i].v);
}
if(k==n-1)
break;
}
完整代码:
1 #include<iostream>
2 #include<algorithm>
3 using namespace std;
4 const int maxn=1e2+5;
5 int mst,k;
6 struct edge
7 {
8 int u,v,w;
9 }e[maxn];
10 int parent[maxn];//并查集
11
12 int find(int x)//查找根节点并且压缩路径
13 {
14 if(parent[x]!=x)
15 parent[x]=find(parent[x]);
16 return parent[x];
17 }
18
19 void unions(int x,int y)//合并两个集合
20 {
21 parent[find(y)]=find(x);
22 }
23
24 bool cmp(const edge&a,const edge&b)
25 {
26 return a.w<b.w;
27 }
28 int main()
29 {
30 int n,m;
31 int a,b,c;
32 cin>>n>>m;
33 for(int i=1;i<=m;++i)
34 {
35 cin>>a>>b>>c;
36 e[i].u=a,e[i].v=b,e[i].w=c;
37 }//初始化边
38 for(int i=1;i<=n;++i)
39 {
40 parent[i]=i;//初始化并查集
41 }
42 sort(e+1,e+1+n,cmp);//快排
43 for(int i=1;i<=m;++i)
44 {
45 if(find(e[i].u)!=find(e[i].v))
46 {
47 ++k;
48 mst+=e[i].w;
49 unions(e[i].u,e[i].v);
50 }
51 if(k==n-1)
52 break;
53 }
54 cout<<mst;
55 }