HDU1272_并查集

题目大意:            让你输入n,m,代表一个迷宫中的两个点,要求这个迷宫中,不能有回路。这是一个无向图,但是其实根据题意来说,最终应该是一棵树。 解题思路:            只要输入的时候一开始判断两个点的父节点是不是相同的,如果相同,那么说明这两个点是连通的,你再加上去,就证明要产生回路啦。所以要排除,,还有,当输入n,m为0时,这时候输出yes,最后再判断下,这个图有没有连通分量就可以了。。。
#include 
#include 
using namespace std; 
const int MAX=100005;
int pre[MAX]; 
int visited[MAX];
int find(int x) 
{ 
	int r, j; 
	r = x; 
	while(pre[r] != r) 
	{ 
		r = pre[r]; 
	} 
	while(pre[x] != r) //优化
	{ 
		j = pre[x];//从底部,一个一个判断上去,如果有一个父节点不是根节点,那么就将它放在根节点上
		pre[x] = r; 
		x = j;
	} 
	return r; 
} 
//int find(int x)
//{
//
//    int r=x;
//
//    while(pre[r]!=r)
//
//        r=pre[r];
//
//    return r;
//}
//void merge(int x,int y)
//{
//
//    int fx,fy;
//
//    fx=find(x);
//
//    fy=find(y);
//
//    if(fx!=fy)
//
//        pre[fx]=fy;
//}

int main(void) 
{
	int n, m, f1, f2;
	while(scanf("%d%d", &n,&m)==2)
	{
		memset(visited,0,sizeof(visited));
		for(int i = 1; i < MAX; i++) 
			pre[i] = i;
		if (n == -1 && m == -1 )
			break;
		if (n == 0 && m == 0 )
		{  
			printf("Yes\n");
			continue;
		}
		f1 = find(n); 
		f2 = find(m); 
		pre[f1]=f2;
		visited[n]=visited[m]=1;
		int minn=200005,maxn=0,flag=0;
		if ( n< minn )     minn = n;           //找到输入 的所有数据中最小的和最大的便于减小最后数组遍历时的复杂度 
			if ( m < minn )     minn = m;
			if ( n> maxn )     maxn = n;
			if ( m > maxn )     maxn = m;
		while(scanf("%d%d", &n,&m)) 
		{ 
			if ( n== 0 && m == 0)
				break;        
			if ( n< minn )     minn = n;           //找到输入 的所有数据中最小的和最大的便于减小最后数组遍历时的复杂度 
			if ( m < minn )     minn = m;
			if ( n> maxn )     maxn = n;
			if ( m > maxn )     maxn = m;

			visited[n]=visited[m]=1;

			f1 = find(n); 
			f2 = find(m); 

			if(f1==f2)
			{
				flag=1;
			}
			else
			{
				pre[f1]=f2;
			}
		} 
		if(flag==1)
			printf ("No\n");
		if (flag==0)
		{
			for (int i = minn; i <= maxn; i++)
			{
				if ( visited[i] && pre[i] == i )
					flag++;
			}
			if (flag == 1)
				printf ("Yes\n");
			else
				printf ("No\n");
		}          
	} 
	return 0; 
}
原文地址:https://www.cnblogs.com/cchun/p/2520177.html