时间限制: 1000 ms 空间限制: 131072 KB 具体限制
题目描述
在一个大家庭中,有n个人,组成一些小家庭(任何两个小家庭之间没有关系)。在任意一个小家庭中,任意两个人都是亲戚关系。
当然,如果b是a的亲戚,且c是b的亲戚,那么c也是a的亲戚。
题目中会给你m对亲戚关系,让你判断k对亲戚关系。
输入
第一行,n和m。
接下来m行,每行两个数x和y,表示x和y是亲戚关系。
第m+2行,k。
接下来k行,每行两个数a和b,表示询问a和b是不是亲戚关系。
n<=100000,m,k<=200000
输出
共k行,每行一个yes或者no,表示每次询问的两个人是不是亲戚关系。
样例输入
10 7 2 4 5 7 1 3 8 9 1 2 5 6 2 3 3 3 4 7 10 8 9
样例输出
Yes No Yes
数据范围限制
提示
输入关系|家庭集合
(2,4) |{1}{2,4}{3}{5}{6}{7}{8}{9}{10}
(5,7) |{1}{2,4}{3}{5,7}{6}{8}{9}{10}
(1,3) |{1,3}{2,4}{5,7}{6}{8}{9}{10}
(8,9) |{1,3}{2,4}{5,7}{6}{8,9}{10}
(1,2) |{1,2,3,4}{5,7}{6}{8,9}{10}
(5,6) |{1,2,3,4}{5,6,7}{8,9}{10}
(2,3) |{1,2,3,4}{5,6,7}{8,9}{10}
因为3和4是亲戚,所以第一行输出yes;
因为7和10不是亲戚,所以第二行输出no;
因为8和9是亲戚,所以第三行输出yes。
这是一道较为明显的并查集的问题(没学的可以去学学,真的很有用)
当每次输入x和y是亲戚关系时,可以先找当前共同的祖先(注:作者习惯小的当祖先)
所以输入找祖先可以这样
int find(int x)
{
if(x==father[x]) return x;
return father[x]=find(father[x])
}
int main(){
scanf("%d%d",&x,&y);
if(x>y) swap(x,y);
int xx=find(x);
int yy=find(y);
father[yy]=xx;
}
询问时再找一次祖先是否相同,because 输入顺序的不同会影响第一次找祖先的不同,第一次找祖先是为了询问时的方便
于是:
for(int i=1;i<=p;i++)
{
scanf("%d%d",&x,&y);
if(find(x)==find(y))
printf("Yes\n");
else
printf("No\n");
}
除此之外一开始每个人自己的祖先是自己
for(int i=1;i<=n;i++) father[i]=i;
将输入输出完善一下,就可以得到AC代码了
下面贴出来
#include<bits/stdc++.h>
using namespace std;
int father[1100001];
int n,m,x,y;
int find(int x)
{
if(father[x]==x) return x;
return father[x]=find(father[x]);
}
int main()
{
// freopen("relation.in","r",stdin);
// freopen("relation.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) father[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
if(x>y) swap(x,y);
int xx=find(x);
int yy=find(y);
if(xx!=yy)
father[yy]=xx;
}
int p;
scanf("%d",&p);
for(int i=1;i<=p;i++)
{
scanf("%d%d",&x,&y);
if(find(x)==find(y))
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
总结:并查集真的有用,这题如果用Bfs或Dfs的话,大概700+bytes了,而且它快啊,咳咳,内个...点个小心心