HDU 1272详细题解(并查集)

来源:互联网 发布:销售单软件 编辑:程序博客网 时间:2024/04/30 07:34

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1272

 

这道题属于并查集。

 

不知道并查集的初学者可以看看我另一篇并查集入门的文章:http://blog.csdn.net/xdz78/article/details/47296585

 

解题思路:

题目的关键是,判断从一个点到任一另一个点是否有两条路径能够到达,在转换一下,我们都知道,判断是否有两条路径就相当于判断一个无向图图是否有回路。所以这道题也就转换成了给出所有边的信息判断是否有回路,这样一想就很简单了,马上想到并查集。

 

为什么并查集能判断一个图是否有回路?大家可以这样想,把一个连通图的各个点加入到一个集合中,说明他们能相互连通,但是若节点x和节点y的根节点相同,也就是说两者已经连通,那再输入一个x y也就是在xy之间再连接一条线,那不就形成了一个回路了么!所以,每次加入边的时候判断两个节点的根节点是否相同,若有相同的根节点,那就说明不符合小希的思路,输出NO

 

有一个重要的细节:很多人都忘了组成的图必须要连通了,所以我们不能只顾着判断是否有回路,若给出的边组成的图不连续,那也得输出NO。我就在这里WA了。

 

有几个需要注意的数据:

0 0         Yes

1 1 00      Yes

1 2 2 10 0   No


#include <stdio.h>#include <stdlib.h>#include <string.h>#define max 100005int flag=0;//flag=1表示不能满足小希的要求int vis[max];//标记节点是否出现过int pre[max];//存放节点的前导int hash[max];//用来判断有几个根节点int ans;//存放根节点的个数void init(){//初始化    int i;    flag=0;    ans=0;    memset(hash,0,sizeof(hash));    memset(vis,0,sizeof(vis));    memset(pre,0,sizeof(pre));    for(i=1;i<=max;i++){//每个节点的前导必须初始化为自己        pre[i]=i;    }}int find(int x){//寻找根节点    int r=x;    while(pre[r]!=r){        r=pre[r];    }    int i=x,j;    while(i!=r){//路径压缩,优化        j=pre[i];        pre[i]=r;        i=j;    }    return r;//返回根节点}void join(int x,int y){    int r_x=find(x),r_y=find(y);    if(r_x==r_y&&x!=y){        flag=1;//形成了回路    }    else pre[r_x]=r_y;}void isunion(){//对出现过的节点计算根节点共有多少个    int i;    for(i=1;i<=max;i++){        if(vis[i])            hash[find(i)]=1;    }    for(i=1;i<=max;i++){        ans+=hash[i];    }    if(ans>1){//若根节点超过一个,说明图未连通,输出No        flag=1;    }}int main(){    int x,y;    while(scanf("%d%d",&x,&y)){        init();        if(x==0&&y==0){            printf("Yes\n");            continue;        }        if(x==-1&&y==-1){            break;        }        vis[x]=1;//把所有出现过的节点标记为已出现        vis[y]=1;        join(x,y);        while(scanf("%d%d",&x,&y)&&x&&y){            vis[x]=1;            vis[y]=1;            join(x,y);        }        isunion();//判断是否是连通图        if(flag){            printf("No\n");        }        else printf("Yes\n");    }    return 0;}


1 0
原创粉丝点击