CodeUp Problem D: More is better

根据题目意思,输入的每一对A、B都是直接朋友,并且最后只会得到一个集合,该集合就是Mr Wang选择的男孩。

因此很容易写出代码,甚至不需要自己构建一个并查集,只需要使用C++的set模板,每次读入一对A、B,就把A、B插入集合,最后集合的大小就是Mr Wang选择的男孩个数。

但是只得了50分,仔细分析一下,可能是“只有一个集合”这一个假定错误,应该在输入数据中包含多个集合的假定下写代码。

转变思路为:

  1. 仍然用数组实现一个并查集。
  2. 另外开一个数组counts,counts[i]表示节点i为根节点时对应集合的大小。
  3. 维护一个计数器maxcnt,用来存当前大小最大的集合数量,每次进行集合合并时都尝试更新maxcnt。
  4. 合并完所有元素后也能得到最大集合的大小。

 

#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;
}

 

posted @ 2020-10-03 20:48  Hidea  阅读(75)  评论(0编辑  收藏  举报