算法理解
并查集是一种树型的数据结构,用于处理一些不交集的合并和查询问题。联合-查找算法(union-find algorithm)定义了两个用于此数据结构的操作。
- Union: 将两个子集合并成同一个集合,根据父节点的引用像根行进直到树根。
- Find: 确定元素属于哪一个集合,方法就是不断的向上查找找到它的根节点,确定两个元素是否在同一个子集,将两棵树合并到一起,这通过将一颗树的根连接到另一棵树的根。
在并查集树中,每个集合的代表即是集合的根节点。
初始化
1 | for(int i=1;i<=n;i++) |
查找
1 | //递归 |
但是这样写数据量大的时候会爆,下面来看路径压缩优化:
路径压缩优化
将某个根结点下的所有子结点都指向该根结点。
1 | int find(int x) |
合并
1 | void merge(int x,int y) //合并集合 |
例题:
A - How Many Tables
Today is Ignatius’ birthday. He invites a lot of friends. Now it’s dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers.
One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table.
For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least.
Input
The input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases.
Output
For each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks.
Sample Input
1 | 2 |
Sample Output
1 | 2 |
AC代码:
1 | #include<iostream> |
B - Ubiquitous Religions
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.
Input
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.
Output
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.
Sample Input
1 | 10 9 |
Sample Output
1 | Case 1: 1 |
Hint
Huge input, scanf is recommended.
题目大意:
有 个学生,编号
,每个学生最多有
个宗教信仰,输入
组数据,每组数据包含
,表示同学
和同学
有相同的信仰,求在
名学生中最多存在多少种不同的宗教信仰。
思路:
与A题一样。
AC代码:
1 | #include <iostream> |