您的位置:首页 > 其它

关于kruskal算法的一些个人理解

2019-01-26 21:09 141 查看

在图论中最小生成树算法中,除了常用的Prim算法之外,还有kruskal算法,该算法也是贪心的思想。

如果说Prim算法是贪心策略是选取当前距离集合最小的边,而kruskal算法的策略测试选择所有边中最小的边,这点和最短路径中的Bellman算法有异曲同工之妙。

详细的判定流程和方法也很简单:

首先要明确的是,选取的边的两个节点都是所谓的“连通量”;所谓连通量和prim算法中的集合大致意义相同,每次选择边,也会将两个点合并为一个连通量,也就是一个集合。

在初始状态下,首先每个点就是一个连通分量。

选择当前所有边中权值最小的边,并且边符合一个条件:边的两边点属于不同的两个联通分量,如果选择该边,将两个连通分量合并为一个;

重复上操作直至所有连通分量变为一个。

此时,就可以找出一个唯一的最小生成树;

对于这个算法,有两个问题需要考虑:

1.如果在不连续构造树的情况下构造生成树,也就是只关注于加边;

2.如果进行不同连通分量的判定;

在这里,我承认自己学艺不精,没有想到之前的并查集神器,也将其中的原理忘得一干二净。

如果使用并查集,就可以很好的同时解决这两个问题;

对于集合的判定合并,只需要每次在集合中查询其根节点,从而判断根节点是否为同一个,不是的话将根节点进行覆盖合并;

同时,在最后,并查集必定变成了一个根节点构成的树,此时,索引之间的关系也揭示了树的结构;

相关代码如下:

[code]struct edge{
int u,v;
int cost;
}E[MAXV];
int kruskal(int n,int m){
int ans=0;//权值和
int Num_Edge=0;//生成的边数
for(int i=1;i<=n;i++){
father[i]=i;
//并查集初始化
}
sort(E,E+m,cmp);
for(int i=0;i<m;i++){
int faU=findFather(E[i].u);
int faV=findFather(E[i].v);
if(faU!=faV){
father[faU]==faV;
ans+=E[i].cost;
Num_Edge++;
if(Num_Edge==n-1)
break;
}
}
if(Num_Edge!=n-1)
return -1;
else
return ans;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: