hdu-1863 smooth engineering (kruskal algorithm + union search)

Topic link: http://acm.hdu.edu.cn/showproblem.php?pid=1863

Kruskal algorithm idea: Goal: get the minimum spanning tree. Steps: Divide the edges into two sets, take out the edge with the smallest weight from the set each time and add it to the set of trees, and get the minimum spanning tree when there are n-1 edges.

hdu-1863 smooth engineering (kruskal algorithm + union search)

#include<cstdio>
#include<cstdlib>
#define MAXN 10000+10
using namespace std;


//par数组用于表示并查集 
int par[MAXN],Rank[MAXN];

//a结构体 表示每条边 
typedef struct{
    int a,b,price;
}Node;
Node a[MAXN];

//用于qsort函数,返回值 a>b +,a<b -,a==b 0;还需要强制类型转换,返回值为int 
int cmp(const void*a,const void *b){
    return ((Node*)a)->price - ((Node*)b)->price;
} 

void Init(int n){
    for(int i=0;i<n;i++){
        Rank[i]=0;
        par[i]=i;//初始化把每个节点的父节点初始化为自己 
    }
}

int find(int x){//找到编号为x的点的父亲节点 
    int root = x;
    while(root != par[root])root = par[root];//找到最父亲的节点??如果两个点互相死循环怎么办? 
    while(x != root){//如果最父亲节点不是它自己,把它的父节点设为最父亲节点,然后继续把它父亲的父亲节点设为最父亲节点,直到 全部父亲节点都为最父亲节点 
        int t = par[x];
        par[x] = root;
        x = t;
    }
    return root;//返回最父亲节点 
}

void unite(int x,int y){
    x = find(x);
    y = find(y);
    if(Rank[x]<Rank[y]){
        par[x]=y;
    }
    else{
        par[y]=x;
        if(Rank[x] == Rank[y]) Rank[x]++;
    }
}

//n为边的数量,m为村庄的数量
int Kruskal(int n,int m){
    //nEdge是边的编号,res是最小代价和 
    int nEdge = 0,res=0;
    //将边按照权值从小到大排序
    qsort(a,n,sizeof(a[0]),cmp); //!!!注意,一定是某一个元素的大小,不能是a,a只是指针大小,如果遇到不是int,就会出错 
    for(int i=0;i<n&&nEdge!=m-1;i++){
        //判断当前这条边的两个端点是否属于同一棵树的并查集 
        //如果不在 就加到一起,然后算出当前最小代价和,指向编号为下一个的边 
        if(find(a[i].a)!=find(a[i].b)) {
            unite(a[i].a,a[i].b);
            res += a[i].price;
            nEdge++;
        }
    }
    //如果加入边的数量小于m-1,则该无向图不连通,等价于不存在最小生成树
    if(nEdge < m-1) res = -1;
    return res; 
} 

int main(){
    int n,m,ans;
    while(scanf("%d%d",&n,&m)&&n!=0){
        Init(m);
        for(int i=0;i<n;i++){
            scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].price);
            //将点编号变为0~m-1
            a[i].a--;
            a[i].b--; 
        }
        ans = Kruskal(n,m);
        if(ans == -1)printf("?\n");
        else printf("%d\n",ans);
    }
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325699211&siteId=291194637