并查集
适用于问题:
给定元素 a , b , c a,b,c a,b,c,告诉你 a , b a,b a,b在同一集合中, b , c b,c b,c也在同一集合中,问 a , c a,c a,c是否在同一集合中?
基本思路:
**思想:**根相同,则二者在同一集合内
-
建立一个映射关系 f ( x ) = y f(x)=y f(x)=y,代表x与y在同一集合中,初始化为 f [ x ] = x f[x]=x f[x]=x,即只有自己和自己有关系
-
建立函数
find_set
,找到关系的根,如:x和z,y和z
在一集合中,则有关系x->z;y->z;z->z
,find_set(x)
就会找到z -
但是有人会有疑问:关系是单向的,x可以到达y,但是z到达不了y,那怎么办?:
答:其实思路不是这样的,而是x的根是z,z的根是z,所以二者是同一集合内的。
-
建立函数
merge_set(x,y)
,将y指向x的根,或x指向y的根都行
亲戚
洛谷P1551
题目背景
若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。
题目描述
规定: x x x 和 y y y 是亲戚, y y y 和 z z z 是亲戚,那么 x x x 和 z z z 也是亲戚。如果 x x x, y y y 是亲戚,那么 x x x 的亲戚都是 y y y 的亲戚, y y y 的亲戚也都是 x x x 的亲戚。
输入格式
第一行:三个整数 n , m , p n,m,p n,m,p,( n , m , p ≤ 5000 n,m,p \le 5000 n,m,p≤5000),分别表示有 n n n 个人, m m m 个亲戚关系,询问 p p p 对亲戚关系。
以下 m m m 行:每行两个数 M i M_i Mi, M j M_j Mj, 1 ≤ M i , M j ≤ N 1 \le M_i,~M_j\le N 1≤Mi, Mj≤N,表示 M i M_i Mi 和 M j M_j Mj 具有亲戚关系。
接下来 p p p 行:每行两个数 P i , P j P_i,P_j Pi,Pj,询问 P i P_i Pi 和 P j P_j Pj 是否具有亲戚关系。
输出格式
p
p
p 行,每行一个 Yes
或 No
。表示第
i
i
i 个询问的答案为“具有”或“不具有”亲戚关系。
样例 #1
样例输入 #1
6 5 3
1 2
1 5
3 4
5 2
1 3
1 4
2 3
5 6
样例输出 #1
Yes
Yes
No
代码
f = [i for i in range(5001)] # 建立关系
def find_set(x):
if x!=f[x]: f[x] = find_set(f[x])
return f[x]
def merge_set(x,y):
x = find_set(x)
y = find_set(y)
if x!=y:
f[x] = y
n,m,p = map(int,input().split())
for _ in range(m):
x,y = map(int,input().split())
merge_set(x,y)
for _ in range(p):
x,y = map(int,input().split())
if find_set(x)!=find_set(y):
print('No')
else:
print('Yes')