本题链接
题目描述
Mr Wang wants some boys to help him with a project. Because the project is rather complex, the more boys come, the better it will be. Of course there are certain requirements.Mr Wang selected a room big enough to hold the boys. The boy who are not been chosen has to leave the room immediately. There are 10000000 boys in the room numbered from 1 to 10000000 at the very beginning. After Mr Wang’s selection any two of them who are still in this room should be friends (direct or indirect), or there is only one boy left. Given all the direct friend-pairs, you should decide the best way.
输入
The first line of the input contains an integer n (0 ≤ n ≤ 100 000) - the number of direct friend-pairs. The following n lines each contains a pair of numbers A and B separated by a single space that suggests A and B are direct friends. (A ≠ B, 1 ≤ A, B ≤ 10000000)
输出
The output in one line contains exactly one integer equals to the maximum number of boys Mr Wang may keep.
样例输入
3
1 3
1 5
2 5
4
3 2
3 4
1 6
2 6
样例输出
4
5
本题在并查集的基础上要求额外的一个信息:集合中结点的个数。用一个manCnt
数组来记录即可,一开始所有结点都是 father 结点,所以manCnt
数组中所有结点的值都应该被初始化成 1(实际上不用初始化所有结点,详见优化时间的第 2 点)。
每当Union
函数把 father 结点fa
合并入 father 结点fb
的时候,令manCnt[fb] += manCnt[fa];
即可更新数据。
优化时间的思路参考了这篇博客:2130 Problem D More is better。
这个题有两个地方可以显著地降低耗时,第 2 点是重点:
max
的求法,不用把所有 father 结点的人数都算完然后最后再遍历一遍,而是每次更新人数的时候顺便更新max
(这一步放在Union
函数即可);father
数组和manCnt
数组在每一轮输入中都无脑初始化所有元素,由于这个题数据量不算小,这一步非常耗时。事实上对于每一轮输入我们都只需要处理出现过的结点即可,未出现的结点无视即可。代码中init
函数负责初始化。Union
的话可能会造成重复初始化的问题,例如a
结点已经是一个大集合的 father 结点,此时又输入数据a b
,那么manCnt[a]
会被错误地初始化为 1,于是我们就需要先把所有输入保存下来,全部初始化完后再处理,代码中的input
负责暂存输入。#include
#include
#include
#define MAX 10000001
using std::vector;
using std::pair;
int father[MAX], manCnt[MAX], max;
int findFather(int x) {
int f = x, temp;
while (f != father[f])
f = father[f];
while (x != father[x]) {
temp = x;
x = father[x];
father[temp] = f;
}
return f;
}
void Union(int a, int b) {
int fa = findFather(a), fb = findFather(b);
if (fa != fb) {
father[fa] = fb;
manCnt[fb] += manCnt[fa];
if (manCnt[fb] > max)
max = manCnt[fb];
}
}
inline void init(int a) {
father[a] = a;
manCnt[a] = 1;
}
int main() {
int n, a, b;
while (scanf("%d", &n) != EOF) {
if (n == 0) {
printf("1\n");
continue;
}
max = 0;
vector<pair<int, int> > input;
for (int i = 0; i < n; ++i) {
scanf("%d%d", &a, &b);
input.push_back( {a, b} );
init(a);
init(b);
}
for (int i = 0; i < input.size(); ++i)
Union(input[i].first, input[i].second);
printf("%d\n", max);
}
return 0;
}
#include
#define MAX 10000001
int father[MAX], manCnt[MAX], max;
int findFather(int x) {
int f = x, temp;
while (f != father[f])
f = father[f];
while (x != father[x]) {
temp = x;
x = father[x];
father[temp] = f;
}
return f;
}
void Union(int a, int b) {
int fa = findFather(a), fb = findFather(b);
if (fa != fb) {
father[fa] = fb;
manCnt[fb] += manCnt[fa];
if (manCnt[fb] > max)
max = manCnt[fb];
}
}
int main() {
int n, a, b;
while (scanf("%d", &n) != EOF) {
if (n == 0) {
printf("1\n");
continue;
}
max = 0;
for (int i = 1; i <= MAX; ++i) {
father[i] = i;
manCnt[i] = 1;
}
for (int i = 0; i < n; ++i) {
scanf("%d%d", &a, &b);
Union(a, b);
}
printf("%d\n", max);
}
return 0;
}
#include
#include
#define MAX 10000001
using std::vector;
int father[MAX], manCnt[MAX];
int findFather(int x) {
int f = x, temp;
while (f != father[f])
f = father[f];
while (x != father[x]) {
temp = x;
x = father[x];
father[temp] = f;
}
return f;
}
void Union(int a, int b) {
int fa = findFather(a), fb = findFather(b);
if (fa != fb) {
father[fa] = fb;
manCnt[fb] += manCnt[fa];
}
}
int main() {
int n, a, b, max;
while (scanf("%d", &n) != EOF) {
if (n == 0) {
printf("1\n");
continue;
}
max = 0;
for (int i = 1; i < MAX; ++i) {
father[i] = i;
manCnt[i] = 1;
}
for (int i = 0; i < n; ++i) {
scanf("%d%d", &a, &b);
Union(a, b);
}
for (int i = 1; i < MAX; ++i)
max = std::max(manCnt[findFather(i)], max);
printf("%d\n", max);
}
return 0;
}