hdu 1233 最小生成树kruskal

来源:互联网 发布:最好的游戏优化软件 编辑:程序博客网 时间:2024/05/17 04:02

http://acm.hdu.edu.cn/showproblem.php?pid=1233

学完kruskal算法,自己的理解就是也是一个贪心的策略,记录下每次的起点和终点,以及他们之间的权值,对边的权值进行排序,每次找出权值比较小的边,判断他与之前所选择的边是否会形成回路,如果不会的话就往生成树中加入这一条边,如果会就舍弃,如何判断回路,就需要用到并查集,找出起点和终点各自的根节点,如果不相同说明是在两个不同的集合之中,(也就意味着不会产生回路)这时候将两个集合合并,并加上这一条边的权值,如果相同就会有回路产生。

附上代码:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define M 110000int u[M];int v[M];int w[M];int p[M];int r[M];int n,m;int ans;int cmp(int i,int j){    return w[i]<w[j];}int find(int a){    return p[a]==a?a:p[a]=find(p[a]); //查找根节点并进行路径压缩}void kruskal(){    for(int i = 0;i < m;i++)    {        int e = r[i];        int x = find(u[e]),y = find(v[e]);        if(x!=y)//不在同一个集合就不会产生回路,合并两个集合        {            p[x] = y;            ans += w[e];        }    }}int main(){    while(scanf("%d",&n)==1 && n)    {        ans = 0;        m = n*(n-1)/2;        for(int i = 1;i <= n;i++)            p[i] = i;        for(int i = 0;i < m;i++)            r[i] = i;        for(int i = 0;i < m;i++)        {            scanf("%d%d%d",&u[i],&v[i],&w[i]);        }        sort(r,r+m,cmp);        kruskal();        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击