CodeUp Problem D: More is better
根据题目意思,输入的每一对A、B都是直接朋友,并且最后只会得到一个集合,该集合就是Mr Wang选择的男孩。
因此很容易写出代码,甚至不需要自己构建一个并查集,只需要使用C++的set模板,每次读入一对A、B,就把A、B插入集合,最后集合的大小就是Mr Wang选择的男孩个数。
但是只得了50分,仔细分析一下,可能是“只有一个集合”这一个假定错误,应该在输入数据中包含多个集合的假定下写代码。
转变思路为:
- 仍然用数组实现一个并查集。
- 另外开一个数组counts,counts[i]表示节点i为根节点时对应集合的大小。
- 维护一个计数器maxcnt,用来存当前大小最大的集合数量,每次进行集合合并时都尝试更新maxcnt。
- 合并完所有元素后也能得到最大集合的大小。
#include <cstdio> #include <algorithm> using namespace std; const int maxn = 10000010; int maxcnt, cnts[maxn]; int father[maxn]; int FindFather(int father[], int b) { int x = b; while (x != father[x]) { x = father[x]; } int a = b; while (a != father[a]) { int z = father[a]; father[a] = x; a = z; } return x; } void Union(int father[], int b1, int b2) { int fa1 = FindFather(father, b1); int fa2 = FindFather(father, b2); if (fa1 != fa2)//这个判断一定一定不能少,如果不先判断fa1是否等于fa2,会导致同一个集合大小翻倍,导致出错 { father[fa1] = fa2; cnts[fa2] += cnts[fa1]; } maxcnt = max(maxcnt, cnts[fa2]); return; } void Init(int father[], int n) { for (size_t i = 1; i <= n; i++) { father[i] = i; cnts[i] = 1; } maxcnt = 1; } int main(int argc, char** argv) { int linen, a, b; while (scanf("%d", &linen) != EOF) { Init(father, maxn); while (linen--) { scanf("%d%d", &a, &b); Union(father, a, b); } printf("%d\n", maxcnt); } return 0; }