题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1272
题目是判断给定的图是否存在环与孤立的点。使用并查集即可判断,如果存在环路,则必有一条边使得当这条边的两端的顶点的根节点属于同一个集合,因而在合并操作的时候判断这条边的两个节点的根节点是否属于同一个集合。孤立的点,则会出现,合并的最后仍至少有两个点的根节点为自身。poj的1308和此题类似
代码如下:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn = 100005 ;
int parent[maxn] ;//记录每个节点的父节点
bool flag ;//标记是否存在环路
bool vis[maxn] ;//标记那些节点存在
//初始化,对并查集的第一个操作
void init()
{
int i ;
flag = 1 ;
for(i = 1 ; i <= maxn ; i ++)
{
parent[i] = i ;
vis[i] = 0 ;
}
}
//查找节点x的根节点
int find_x(int x)
{
int r = x ;
while(r!=parent[r])
r = parent[r] ;
return r ;
}
//合并操作
void join(int x , int y)
{
int p = find_x(x) ;
int q = find_x(y) ;
//判断根节点是否相同,如果相同,则表示则两个点已在同一个集合中,则此边的加入会形成环路
if(p==q)
{
flag = false ;
return ;
}
else
{
parent[p] = q ;
}
return ;
}
//查找是否有孤立点的存在
bool count(int x)
{
int i ;
int sum = 0 ;
for(i = 1 ; i <= x ;i ++)
{
if(parent[i]==i && vis[i])
{
sum ++ ;
}
if(sum > 1)
{
return 0 ;
}
}
return 1 ;
}
int main()
{
int p ;
int q ;
int w ;//用于保存所有节点的最大编号,大于此编号的节点不用查找时访问
//freopen("data.in" ,"r" , stdin) ;
while(scanf("%d%d" , &p , &q)!=EOF)
{
init() ;
if(p==-1&& q==-1)
break ;
//注意如果直接为空
if(p==0 && q== 0 )
{
printf("Yes\n") ;
continue ;
}
else {
join(p ,q) ;
vis[p] = vis[q] = 1 ;
w = q > p ? q : p ;
while(scanf("%d%d" , &p ,&q)&&(p||q))
{
vis[p] = vis[q] = 1 ;
if(p!=q)
join(p ,q) ;
if(w < p)
w = p ;
if(w < q)
w = q ;
}
if(flag && count(w))
{
printf("Yes\n") ;
}
else
{
printf("No\n") ;
}
}
}
return 0;
}