TZOJ 5782: 亲戚/6310: 亲戚2 并查集/路径压缩/优化

先来看看代码清单:

(1)初始化

for(int i=1;i<=n;i++)f[i] = i; //初始化每个的爹是自己 

因为每个元素属于单独的一个集合,所以每个元素以自己作为结点

(2)寻找根结点编号并压缩路径

int find(int x)
{
        //如果第x个人的爹f[x]不是自己,那么就继续去寻找爹中爹,最终把自己的祖先认作自己的爹
    if(f[x]!=x) f[x] = find(f[x]); 
    return f[x];
}

(3)合并两个集合

void uon(int x,int y)
{
    x = find(x);y = find(y); //找到x,y的祖先
    f[y] = x; //让y的祖先认x的祖先作为爹 
}

(4)判断元素是否在同一个集合

int judge(int x,int y)
{
    x = find(x);
    y = find(y);
    if(x==y)return 1;
    else return 0;
}

(5)判断一个家族的人数,需要将合并函数uon改一下

void uon(int r1,int r2)
{
    if(a[r1]<a[r2])swap(r1,r2); //我们保证让人少的并到人多的
    f[r2] = r1; //r2并入到r1
    a[r1] += a[r2]; //把两个家族的人加上到r1家族中
}

5782: 亲戚 

描述

或许你并不知道,你的某个朋友是你的亲戚。他可能是你的曾祖父的外公的女婿的外甥女的表姐的孙子。如果能得到完整的家谱,判断两个人是否是亲戚应该是可行的,但如果两个人的最近公共祖先与他们相隔好几代,使得家谱十分庞大,那么检验亲戚关系实非人力所能及。在这种情况下,最好的帮手就是计算机。为了将问题简化,你将得到一些亲戚关系的信息,如Marry和Tom是亲戚,Tom和Ben是亲戚,等等。从这些信息中,你可以推出Marry和Ben是亲戚。请写一个程序,对于我们的关于亲戚关系的提问,以最快的速度给出答案。

 

 

输入

 

 

输入由两部分组成。

第一部分以N,M开始。N为问题涉及的人的个数(1≤N≤20000)。这些人的编号为1,2,3,…, N。下面有M行(1≤M≤1000000),每行有两个数ai,bi,表示已知ai和bi是亲戚。

第二部分以Q开始。以下Q行有Q个询问(1≤ Q ≤1000000),每行为ci,di,表示询问ci和di是否为亲戚。

 

 

输出

 

 

对于每个询问ci,di,输出一行:若ci和di为亲戚,则输出“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

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int f[20005];
 4 int n,m,q;
 5 int find(int x)
 6 {
 7     if(f[x]!=x) f[x] = find(f[x]);
 8     return f[x];
 9 }
10 void uon(int r1,int r2)
11 {
12     f[r2] = r1;
13 }
14 int judge(int x,int y)
15 {
16     x = find(x);
17     y = find(y);
18     if(x==y)return 1;
19     else return 0;
20 }
21 int main()
22 {
23     cin>>n>>m;
24     for(int i=1;i<=n;i++)f[i] = i;
25     for(int i=1;i<=m;i++)
26     {
27         int x,y;
28         scanf("%d %d",&x,&y);
29         int r1 = find(x);
30         int r2 = find(y);
31         if(r1!=r2)uon(r1,r2);
32     }
33     cin>>q;
34     while(q--)
35     {
36         int x,y;
37         scanf("%d %d",&x,&y);
38         if(judge(x,y))printf("Yes\n");
39         else printf("No\n");
40     }
41      return 0;
42 }

 

6310: 亲戚2

描述

 

若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的某个人所在家族的人数。

规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。

 

输入

 

第一行:三个整数n,(n≤100,000,m≤200,000),分别表示有n个人,m个信息。

以下m行:信息包含两种形式:

M a b:表示a和b具有亲戚关系。

Q a:要求输出a所在家族的人数。

 

输出

 

要求输出a所在家族的人数。

 

样例输入

 

5 10
M 3 2
Q 4
M 1 2
Q 4
M 3 2
Q 1
M 3 1
Q 5
M 4 2
Q 4

样例输出

 

1
1
3
1
4

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int f[100005],a[100005];
 4 int n,m,q;
 5 char c;
 6 int find(int x)
 7 {
 8     if(f[x]!=x) f[x] = find(f[x]);
 9     return f[x];
10 }
11 void uon(int r1,int r2)
12 {
13     if(a[r1]<a[r2])swap(r1,r2);
14     f[r2] = r1;
15     a[r1] += a[r2]; //把两个家族的人加上 
16 }
17 int judge(int x,int y)
18 {
19     x = find(x);
20     y = find(y);
21     if(x==y)return 1;
22     else return 0;
23 }
24 int main()
25 {
26     scanf("%d %d",&n,&m);
27     for(int i=1;i<=n;i++)f[i] = i,a[i] = 1;
28     for(int i=1;i<=m;i++)
29     {
30         scanf("\n%c",&c);
31         if(c=='M')
32         {
33             int x,y;
34             scanf("%d %d",&x,&y);
35             int r1 = find(x);
36             int r2 = find(y);
37             if(r1!=r2)uon(r1,r2);
38         }
39         else
40         {
41             int x;
42             scanf("%d",&x);
43             printf("%d\n",a[find(x)]);
44         }
45     }
46 
47      return 0;
48 }

 

posted @ 2022-12-30 21:09  CRt0729  阅读(138)  评论(0编辑  收藏  举报