Description
从前有一个国王,他叫小鑫。有一天,他想建一座城堡,于是,设计师给他设计了好多简易图纸,主要是房间的连通的图纸。小鑫希望任意两个房间有且仅有一条路径可以相通。小鑫现在把设计图给你,让你帮忙判断设计图是否符合他的想法。比如下面的例子,第一个是符合条件的,但是,第二个不符合,因为从5到4有两条路径(5-3-4和5-6-4)。
Input
多组输入,每组第一行包含一个整数m(m < 100000),接下来m行,每行两个整数,表示了一条通道连接的两个房间的编号。房间的编号至少为1,且不超过100000。
Output
每组数据输出一行,如果该城堡符合小鑫的想法,那么输出"Yes",否则输出"No"。
Sample Input
5
2 5
2 3
1 3
3 6
4 6
6
1 2
1 3
3 4
3 5
5 6
6 4
Sample Output
Yes
No
代码:
(此题挺难,一输入0 0时保证输出Yes。二保证不出现环,也就是每添加新元素时判断两者祖宗是否一样,若一样,合并函数返回值0,不一样,返回1,在后面控制flag。三保证只是一个集合,这一点好难写程序,下面代码中引入了一个t值,增加元素,标记一下,判断是否为新元素,如果增加n个新元素,t就变为t+n,此时如果只有一个集合,那么合并的次数也会为n,在返回值为1的情况下t--,最终t=1。如果有多个集合,t最终大于1。 为什么要这样判断集合,因为元素数不是连续的,不能用传统的找祖宗个数=1来判断,此法很好很妙,利用了键。)
#include <stdio.h>
#include <string.h>
int bin[100001];
int wz[1000001];
int find(int x)
{
int r = x;
while (bin[r]!=r)
{
r=bin[r];
}
int i = x;
while(bin[i]!=r)
{ int j;
j = bin[i];
bin[i] = r;
i = j;
}
return r;
}
int merge(int x,int y)
{
int fx,fy;
fx = find(x);
fy = find(y);
if(fx != fy)
{
bin[fy] = fx;
return 1;
}
else
return 0;
}
int main ()
{
int x,y,flag,i,t,T,j;
while (~scanf("%d",&T))
{
scanf("%d%d",&x,&y);
memset(wz,0,sizeof(wz));
memset(bin,0,sizeof(bin));
for (i = 0;i < 100001;i++)
{
bin[i] = i;
}
merge(x , y);
wz[x] = 1;
wz[y] = 1;
t = 1; (进一步解释t:可理解为键,初始连接两个,键为1,同一集合内增加n个新元素,)
flag = 1;
for(j = 1;j<=T-1;j++) (无论怎么连,需要n个新键,r个集合需要的新键为n-r+1个)
{
scanf("%d%d",&x,&y);
if (wz[x] == 0)
{
t++;
wz[x] = 1;
}
if (wz[y] == 0)
{
t++;
wz[y] = 1;
}
int z = merge(x,y);
if (z == 1)
t--;
else
flag = 0;
}
if (flag == 1&&t==1)
printf ("Yes\n");
else
printf ("No\n");
}
return 0;
}