并查集并查集并查集

题目地址:http://www.tzcoder.cn/acmhome/contestRankList.do?&contestId=1144

难度D<C<A<B

并查集模板(无非就是三个函数Find(查找父亲),Join(加入并查集),init(初始化)和一个数组F[N](N为人数))

A题

描述

There are so many different religions in the world today that it is difficult to keep track of them all. You are interested in finding out how many different religions students in your university believe in.

You know that there are n students in your university (0 < n <= 50000). It is infeasible for you to ask every student their religious beliefs. Furthermore, many students are not comfortable expressing their beliefs. One way to avoid these problems is to ask m (0 <= m <= n(n-1)/2) pairs of students and ask them whether they believe in the same religion (e.g. they may know if they both attend the same church). From this data, you may not know what each person believes in, but you can get an idea of the upper bound of how many different religions can be possibly represented on campus. You may assume that each student subscribes to at most one religion.

输入

The input consists of a number of cases. Each case starts with a line specifying the integers n and m. The next m lines each consists of two integers i and j, specifying that students i and j believe in the same religion. The students are numbered 1 to n. The end of input is specified by a line in which n = m = 0.

输出

For each test case, print on a single line the case number (starting with 1) followed by the maximum number of different religions that the students in the university believe in.

样例输入

10 9
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
10 4
2 3
4 5
4 8
5 8
0 0

样例输出

Case 1: 1
Case 2: 7

提示

Huge input, scanf is recommended.
题意
给你编号1-N个人,假设每个人最多可以信奉1个宗教,给你M队编号,每两个人属于1个宗教,问N个人最多有几个不同的宗教
题解
由于这里N有点大,得用压缩路径来优化查找速度
代码
 1 #include<cstdio>
 2 int F[50005],Religion;
 3 int Find(int x)
 4 {
 5     return F[x]==x?x:F[x]=Find(F[x]);//压缩路径
 6 }
 7 void init(int n)
 8 {
 9     for(int i=1;i<=n;i++)
10         F[i]=i;
11 }
12 void Join(int a,int b)
13 {
14     int fx=Find(a);
15     int fy=Find(b);
16     if(fx!=fy)//两人未连通的情况
17         F[fx]=fy,Religion--;
18 }
19 int main()
20 {
21     int n,m,u,v,Case=1;
22     while(scanf("%d%d",&n,&m),n||m)
23     {
24         Religion=n;
25         init(n);
26         for(int i=0;i<m;i++)
27         {
28             scanf("%d%d",&u,&v);
29             Join(u,v);
30         }
31         printf("Case %d: %d\n",Case++,Religion);
32     }
33     return 0;
34 }

B题

描述

2010年是xx国一个多灾多难的一年,灾难使该国的通讯系统遭到了重创,全国共有n个通讯站点,分别从0到n-1进行编号,通讯部门对每两个站点的线路进行了检测,现在要你确定有哪些站点是彼此连通的。

输入

输入数据有多组,每组数据的第一行包含两个整数n和m,其中n为通讯站点个数,接下来有m行,每一行有2个整数a和b,表示站点a和b通讯正常。其中1<=n<=250。
输入以EOF结束。

输出

针对每组输入,将所有连通的站点进行分组,并将每组按照站点从小到大的顺序输出,如果有多组,所有的组根据每组最小的站点编号进行从小到大的排序后输出。
每组数据输出之后加一个空行

样例输入

3 3
0 1
1 2
0 2
5 1
0 2

样例输出

0 1 2

0 2
1
3
4

题意

如上

题解

唯一一点需要注意的是要按站点编号从小到大输出,我就想了个O(N^2)的,开个Vis数组用来标记是否输出过

代码

 1 #include<iostream>
 2 using namespace std;
 3 int F[255];
 4 int Find(int x)
 5 {
 6     return F[x]==x?x:F[x]=Find(F[x]);
 7 }
 8 void init(int n)
 9 {
10     for(int i=0;i<n;i++)
11         F[i]=i;
12 }
13 void Join(int a,int b)
14 {
15     int fx=Find(a);
16     int fy=Find(b);
17     if(fx!=fy)
18         F[fx]=fy;
19 }
20 int main()
21 {
22     int n,m,u,v;
23     while(cin>>n>>m)
24     {
25         init(n);
26         for(int i=0;i<m;i++)
27         {
28             cin>>u>>v;
29             Join(u,v);
30         }
31         int Vis[255]={0};
32         for(int i=0;i<n;i++)
33         {
34             if(!Vis[i])
35             {
36                 Vis[i]=1;
37                 printf("%d",i);
38                 for(int j=i+1;j<n;j++)
39                 {
40                     if(!Vis[j]&&Find(i)==Find(j))//找父亲,若父亲相同则属于同一个
41                     {
42                         Vis[j]=1;
43                         printf(" %d",j);
44                     }
45                 }
46                 puts("");
47             }
48         }
49         puts("");
50     }
51     return 0;
52 }

C题

描述

某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?

输入

测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。
注意:两个城市之间可以有多条道路相通,也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。

输出

对每个测试用例,在1行里输出最少还需要建设的道路数目。

样例输入

4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0

样例输出

1
0
2
998

题意

如上

题解

连接N个点至少需要N-1条边,若用并查集连通两个点,需要的边减1

代码

 1 #include<iostream>
 2 using namespace std;
 3 int F[1005],road;
 4 int Find(int x)
 5 {
 6     return F[x]==x?x:F[x]=Find(F[x]);
 7 }
 8 void init(int n)
 9 {
10     for(int i=1;i<=n;i++)
11         F[i]=i;
12 }
13 void Join(int a,int b)
14 {
15     int fx=Find(a);
16     int fy=Find(b);
17     if(fx!=fy)
18         F[fx]=fy,road--;
19 }
20 int main()
21 {
22     int n,m,u,v;
23     while(cin>>n,n)
24     {
25         init(n);
26         road=n-1;
27         cin>>m;
28         for(int i=0;i<m;i++)
29         {
30             cin>>u>>v;
31             Join(u,v);
32         }
33         cout<<road<<endl;
34     }
35     return 0;
36 }

D题

描述

There are some people traveling together. Some of them are friends. The friend relation is transitive, that is, if A and B are friends, B and C are friends, then A and C will become friends too.

These people are planning to book some rooms in the hotel. But every one of them doesn't want to live with strangers, that is, if A and D are not friends, they can't live in the same room.

Given the information about these people, can you determine how many rooms they have to book at least? You can assume that the rooms are large enough.

输入

The first line of the input is the number of test cases, and then some test cases followed.

The first line of each test case contain two integers N and M, indicating the number of people and the number of the relationship between them. Each line of the following M lines contain two numbers A and B (1 ≤ A ≤ N , 1 ≤ B ≤ N , A ≠ B), indicating that A and B are friends.

You can assume 1 ≤ N ≤ 100, 0 ≤ M ≤ N * (N-1) / 2. All the people are numbered from 1 to N.

输出

Output one line for each test case, indicating the minimum number of rooms they have to book.

样例输入

3
5 3
1 2
2 3
4 5
5 4
1 2
2 3
3 4
4 5
10 0

样例输出

2
1
10

提示

In the first sample test case, there are 5 people. We see that 1,2,3 can live in a room, while 4,5 can live in another room. So the answer should be 2. Please note even though 1 and 3 are not "direct" friends, but they are both 2's friends, so 1 and 3 are friends too.

In the second sample test case, there are 5 people, any two of them will become friends. So they can live in one room.

In the third sample test case, there are 10 people and no friend relationship between them. No two people can live the same room. They have to book 10 rooms.

题意

求有多少个团队

题解

没啥好说的,模板

代码

 1 #include<iostream>
 2 using namespace std;
 3 int F[105];
 4 int Find(int x)
 5 {
 6     return F[x]==x?x:F[x]=Find(F[x]);
 7 }
 8 void init()
 9 {
10     for(int i=1;i<=100;i++)
11         F[i]=i;
12 }
13 void Join(int a,int b)
14 {
15     int fx=Find(a);
16     int fy=Find(b);
17     if(fx!=fy)
18         F[fx]=fy;
19 }
20 int main()
21 {
22     int t;
23     cin>>t;
24     while(t--)
25     {
26         init();
27         int n,m,u,v;
28         cin>>n>>m;
29         for(int i=0;i<m;i++)
30         {
31             cin>>u>>v;
32             Join(u,v);
33         }
34         int cnt=0;
35         for(int i=1;i<=n;i++)
36             if(F[i]==i)//说明这是编号i的1个团队
37                 cnt++;
38         cout<<cnt<<endl;
39     }
40     return 0;
41 }

posted on 2018-03-13 19:00  大桃桃  阅读(382)  评论(1编辑  收藏  举报

导航