杭电 hdu 1272 小希的迷宫 和 hdu 1325 Is It A Tree?(最下生成树 + 并查集)

时间:2021-08-18 12:56:53

杭电  hdu  1272   小希的迷宫   和     hdu 1325  Is It A Tree?(最下生成树 + 并查集)



小希的迷宫

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 33084    Accepted Submission(s): 10193


Problem Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走。但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了房间A和B,那么既可以通过它从房间A走到房间B,也可以通过它从房间B走到房间A,为了提高难度,小希希望任意两个房间有且仅有一条路径可以相通(除非走了回头路)。小希现在把她的设计图给你,让你帮忙判断她的设计图是否符合她的设计思路。比如下面的例子,前两个是符合条件的,但是最后一个却有两种方法从5到达8。 
杭电  hdu  1272   小希的迷宫   和     hdu 1325  Is It A Tree?(最下生成树 + 并查集)
 
Input 输入包含多组数据,每组数据是一个以0 0结尾的整数对列表,表示了一条通道连接的两个房间的编号。房间的编号至少为1,且不超过100000。每两组数据之间有一个空行。 
整个文件以两个-1结尾。
 
Output 对于输入的每一组数据,输出仅包括一行。如果该迷宫符合小希的思路,那么输出"Yes",否则输出"No"。
 
Sample Input
6 8  5 3  5 2  6 4
5 6 0 0

8 1 7 3 6 2 8 9 7 5
7 4 7 8 7 6 0 0

3 8 6 8 6 4
5 3 5 6 5 2 0 0

-1 -1
 
Sample Output
Yes
Yes
No
 
Author Gardon  
Source HDU 2006-4 Programming Contest  
Recommend lxj   |   We have carefully selected several similar problems for you:  1856 1102 1863 1879 1301   






题意:就是告诉你几组两个点向连通,然后所有的连通点组合,是否可以组合成一棵树,树的要求是中间没有环,而且不是森林






题解:通过并查集来进行最小生成树的生成,将每个点进行连接,给予祖先节点。
然后是解决环和森林
环:只要两个点的祖先节点是相同的,那这两个点连接起来,肯定有环
森林:要是给出的所有的点,比加入树的点要多,就表明不止一棵树






#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <algorithm>

using namespace std;

const int maxn = 100005;

int father[maxn]; //存放父亲节点
int cont[maxn]; //记录每个点所在的树中的结点树
int flag; //判断时候是树0为是,1为不是
int num[maxn]; //记录输入所给的点
int sum;

void Init (){
int i;

memset (num, 0, sizeof (num));
sum = 0;
flag = 0;
for (i = 1; i < maxn; ++i){
father[i] = i; //初始化,将所以点的父亲结点赋值为自己
cont[i] = 1; //初始化,最开始的每个结点所在的树结点数为1,就是它本身
}
}

int Find (int x){ //寻找祖先结点
int rt = x;

if (father[x] != x){
rt = Find(father[x]); //**********************************************************************
// father[x] = rt; //就是这里,我一直以为是剪枝效果,但是一加上这句话,就会报错,
} //要是有大神看到,知道为什么,请指教,指点一下我,谢谢
return rt; //************************************************************************
}


void Union (int a, int b){
int fa = Find (a);
int fb = Find (b);

if (fa == fb) //要是有相同的祖先,那么就表示这两个点连接,就会产生环
flag = 1;
else{
father[fa] = fb;
cont[fb] += cont[fa]; //将fa所在的树的结点个数加到fb中
sum = cont[fb]; //随便选取一棵树的结点个数,只要比总的少,就表明有多棵树
}
}

int main (){
int a, b, i;

while (scanf ("%d%d", &a, &b) != EOF){
Init();
num[a] = num[b] = 1;
if (a < 0 && b < 0) break;
if (a == 0 && b == 0){ //一个结点都没有,表明正确,是可以的
printf ("Yes\n");
continue;
}
Union(a, b);
while (scanf ("%d%d", &a, &b) != EOF){
if (a == 0 && b == 0) break;
num[a] = num[b] = 1;
Union(a, b);
}
int sum1 = 0;
for (i = 1; i < maxn; ++i){ //通过结点数,来判断是否是森林
if (num[i] == 1)
sum1++;
}
if (sum < sum1)
flag = 1;
if (flag)
printf ("No\n");
else
printf ("Yes\n");
}

return 0;
}