kruskal是求最小生成树的算法。
首先,kruskal就是把所有边按照权值从小到大的顺序排列,这一步可以直接使用sort,然后依次考查每一条边,设w=(u,v)表示从u到v的一条边的权值为w,则有:
情况1:u和v在同一个连通分量中,则加入(u,v)后会形成环,因此不能选择。
情况2:u和v不在同一个连通分量中,那么加入(u,v)一定是最优的,为什么呢?这个可以用反证法证明一下,在这里也就不多说啦。
这里有一份kruskal的实现代码(这份代码来自kuangbin神牛,final爷哦,大家可以去他博客学习www.kuangbin.net):
代码纯手打,所以没有语法高亮等,哈哈。
const int MAXN=110;//最大节点数
const int MAXM=1e6;//最大边数
struct Edge
{
int u,v,w;
}edge[MAXM];//用于储存边的信息,节点u和v之间的权值为w,u,v之间可以有多条边,不影响的
int father[MAXN];//并查集的应用,用于判断2个节点是否在同一个连通变量中
int tot;//记得初始化为0或1
void addedge(int u,int v,int w)
{
edge[tot].u=u;
edge[tot].v=v;
edge[tot++].w=w;
}
int find_set(int x)
{
if(father[x]==-1)
return x;
else
return father[x]=find_set(father[x]);
}//路径压缩
bool cmp(Edge x,Edge y)
{
return x.w<y.w;
}
int kruskal(int n)//传入点数,返回最小权值,若不连通,返回-1
{
sort(edge,edge+tot,cmp);
memset(father,-1,sizeof(father));
int ans=0;
int num=0;
for(int i=0;i<tot;i++)//我就有一次错写为i<n,囧,这里是从边是0~tot-1,随机应变咯
{
int u=edge[i].u;
int v=edge[i].v;
int w=edge[i].w;
int fau=find_set(father[u]);
int fav=find_set(father[v]);
if(fau!=fav)
{
ans+=w;
num++;
father[fau]=fav;
}
if(num==n-1)
break;
}
if(num<n-1)
return -1;
else
return ans;
}
就到这里啦,我会继续补充的。