亲戚(File IO): input:relation.in output:relation.out

时间限制: 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了,而且它快啊,咳咳,内个...点个小心心

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值