求解最小生成树的算法 kruskal算法(附模板)

今天来写一下最小生成树的两种的算法,毕竟能把东西完整的表述出来才是真正的理解了。

prim算法的链接http://blog.csdn.net/winoros/article/details/21284783


kruskal算法思路为贪心

算法思路

1)将边按边权升序排序。

2)然后从最小的边开始选取加入图中,如果加入这条边后出现了环(也就是这条边的两个端点都已经有边与之相连了),那么这时就破坏了生成树的性质, 所以就不选择这条边。

3)这种选择一直进行到图中出现了一个生成树为止。

算法正确性的证明

1)假设一颗最小生成树U,我们通过kruskal得到的树为V,两颗树中不同的边为u1, u2, u3, ……v1, v2, v3……(它们均按边权从小到大排序),两棵树中相同的边在边集T中。

2)我们把v1放入V中,明显,放入时都会在U中出现一个环,而且这个环中肯定会有u1, u2, u3, ……中的边,我们把其中最大的ui删去,得到一棵新的生成树P。

3)这时,我们把P和V做对比,明显,加入的v1取代了U中的某条边,如果v1小于删去的ui,那么P<U,这与U是最小生成树相矛盾。而如果v1大于删去的ui,那么ui应该是在v1之前考虑的,而v1又是在v2, v3,……之前考虑的,从而我们考虑有kruskal生成的树V,根据V的生成思路,V中之所以没有ui,是因为ui和T中的某些边构成了环。但是,ui和T又同时都在U中,从而也就是说U中出现了环,这与U的初始假设矛盾。所以ui和v1的权重是相同的。因此,新树P和假设的U的权重的是相同的。

4)现在对P和V重复1)~3)知道两者没有不同的边为止。由于P的权重一直都和所假设的最小生成树U的权重相等。所以,V和U的权重也是相等的。

综上,我们证明了树V确实是一颗最下生成树。


算法的具体实现中,判断加入一条边后是否会出现环可以使用并查集优化。

时间复杂度O(Elog2E),E为图的边数目,主要时间浪费在对边的排序上。所以相对prim算法,它更适合求稀疏图

 下面贴出代码

//Kruskal 算法
//made by winoros


struct edge {
    int from, int to, int cost;
    friend bool operator < (edge a, edge b) {
        return a.cost < b.cost
    }
}e[];

//并查集内容
void ufs_init(int n) {
    for(int i = 0; i < n; i++) p[i] = i;
}

ind find(int i) {
    return f[i] == I ? i : f[i] = find(f[i]);
}

int merge(int i, int j) {
    f[find(i)] = find(j);
}

int p[];//并查集中点的父亲节点

//并查集结束


int kru(int n, int all) { //n 代表边数, all代表点的个数
    int sum = 0, cnt = 0;
    sort(e, e + n);
    ufs_init(n);
    for(int i = 0; i < n; i++) {
        if(find(e[i].from) != find(e[i].to))
            sum += e[i].cost, merge(e[i].from, e[i].to);
            if(++cnt == all - 1) break;
    }
    
    return cnt == all - 1 ? sum : -1;//这里返回的是最小生成树的总边权
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值