生成树指无向图中包含图的所有节点,边集为原图子集的图;
最小生成树指权值最小的生成树,对于包含n个节点的无向图来说,它的最小生成树包含n-1条边。
kruskal算法求解最小生成树的基本步骤如下:
1.数据结构表达:
u[maxn],v[maxn],w[maxn] 用来表示边的信息,在kruskal算法中,虽然最小生成树是是无向图,但是也只需要存储一条边的信息即可,例如若已存储(1,2,3),则边(2,1,3)便没有必要存储!
p[maxn] 存储节点所在连通分量的父亲下标
r[maxn] 存储边排序后的下标,间接排序法!
kruskal算法自然语言描述
1,对所有边排序
2, 从最小的边到最大的边
{
如果这条边的首节点和尾节点不在一个连通分量,把他们合并。
}
3,代码描述
for(int i=1;i<=m;i++)//初始化每个节点的父亲为自己
p[i]=i;
for(int i=1;i<=m;i++)
r[i]=i;
sort(r+1,r+m+1,cmp);//间接排序
for(int i=1;i<=m;i++) //遍历m条边
{
int e=r[i];
int x=Find(u[e]);
int y=Find(v[e]);
if(x!=y) //如果这条边的始点和终点不在一个连通分量
{
ans+=w[e];
p[x]=y;
}
}
以下是杭电1102题目代码(AC)
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int MaxN=105;
const int MaxM=MaxN*(MaxN+1);
int weight[MaxN][MaxN];
int u[MaxM],v[MaxM],w[MaxM];
int p[MaxM];
int r[MaxM];
int cmp(const int i,const int j)
{
return w[i]<w[j];
}
int Find(int x)
{
return p[x]==x?x:p[x]=Find(p[x]);
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&weight[i][j]);
}
}
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int first,last;
scanf("%d%d",&first,&last);
weight[first][last]=weight[last][first]=0;
}
int num=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i!=j)
{u[num]=i; v[num]=j; w[num]=weight[i][j]; num++; }
}
}
int ans=0;
int m=num-1;
for(int i=1;i<=m;i++)
p[i]=i;
for(int i=1;i<=m;i++)
r[i]=i;
sort(r+1,r+m+1,cmp);
for(int i=1;i<=m;i++)
{
int e=r[i];
int x=Find(u[e]);
int y=Find(v[e]);
if(x!=y)
{
ans+=w[e];
p[x]=y;
}
}
printf("%d\n",ans);
}
return 0;
}
/*
4
0 300 500 200
300 0 400 100
500 400 0 600
200 100 600 0
*/