并查集,离散化
题目意思:
n对朋友(n <= 100000),每个人都有一个编号(编号最大值10000000)。
问:要求最后挑选出的人之间都是朋友关系,可以说直接的,也可以是间接地。问最多可以挑选出几个人(最少挑一个)。
在基础的并查集上加个数组记录集合的数量。
本题要点:
1、人的编号 很大(编号最大值10000000),需要离散化。
2、sum[i] 表示以i为根的集合,该集合有多少数。
每一对朋友,合并。最后,扫描所有的 sum[i], 找出最大值即可。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MaxN = 100010;
int a[MaxN], b[MaxN], c[MaxN * 2], d[MaxN * 2];
int fa[MaxN * 2];
int sum[MaxN * 2];
int n, m;
int get(int x)
{
if(fa[x] == x)
return x;
return fa[x] = get(fa[x]);
}
void merge(int x, int y)
{
int fax = get(x);
int fay = get(y);
if(fax != fay)
{
fa[fax] = fay;
sum[fay] += sum[fax];
}
}
void discrete()
{
m = 0;
sort(c + 1, c + 2 * n + 1);
for(int i = 1; i <= 2 * n; ++i)
{
if(1 == i || c[i] != c[i - 1])
{
d[++m] = c[i];
}
}
for(int i = 0; i < n; ++i)
{
a[i] = lower_bound(d + 1, d + m + 1, a[i]) - d;
b[i] = lower_bound(d + 1, d + m + 1, b[i]) - d;
// printf("a[%d] = %d, b[%d] = %d\n", i, a[i], i, b[i]);
}
}
int main()
{
while(scanf("%d", &n) != EOF)
{
if(0 == n)
{
printf("1\n");
continue;
}
int cnt = 0;
for(int i = 0; i < n; ++i)
{
scanf("%d%d", &a[i], &b[i]);
c[++cnt] = a[i], c[++cnt] = b[i];
}
discrete();
for(int i = 1; i <= m; ++i)
{
sum[i] = 1, fa[i] = i;
}
for(int i = 0; i < n; ++i)
{
merge(a[i], b[i]);
}
int ans = -1;
for(int i = 1; i <= m; ++i)
{
ans = max(ans, sum[get(i)]);
}
printf("%d\n", ans);
}
return 0;
}
/*
4
1 2
3 4
5 6
1 6
4
1 2
3 4
5 6
7 8
*/
/*
4
2
*/