zoukankan      html  css  js  c++  java
  • Problem D: More is better

    Description

    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.

    Input

    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)

    Output

    The output in one line contains exactly one integer equals to the maximum number of boys Mr Wang may keep.

    Sample Input

    3
    1 3
    1 5
    2 5
    4
    3 2
    3 4
    1 6
    2 6
    
    

    Sample Output

    4
    5

     题目链接:More is better

    二刷代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int MAX=1e5+2;
    int cnt[MAX], father[MAX];
    int findFather(int x){
        if(x != father[x]) father[x] = findFather(father[x]);
        return father[x];
    }
    int main(){
        int i, n, u, v, ans;
        while(cin >> n){
            for(i=0; i<MAX; i++){
                cnt[i] = 1;
                father[i] = i;
            }
            ans = 1;
            for(i=0; i<n; i++){
                scanf("%d %d", &u, &v);
                u = findFather(u);
                v = findFather(v);
                if(u != v){
                    cnt[u] += cnt[v];
                    ans = max(ans, cnt[u]);
                    father[v] = u;
                }
            }
            printf("%d
    ", ans);
        }
        return 0;
    }

    总结:比第一次写的代码简洁为了一些,代码的逻辑也更加清晰了。

    最终AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int MAX=1e7+2; 
    int father[MAX], cnt[MAX];
    int findFather(int x){ //这段代码值得细细品味 
        if(x == father[x]) return x;
        else{
            int temp = findFather(father[x]);
            father[x] = temp;
            return temp;
        }
    }
    int main(){
        int i, n, u, v, num, ans;
        while(cin >> n){
            if (n == 0){
                cout << 1 << endl;
                continue;
            }
            for(i=1; i<MAX; i++){
                cnt[i] = 1;
                father[i] = i;
            }
            ans = 1;
            for(i=0; i<n; i++){
                scanf("%d %d", &u, &v); //这里如果写成 cin > > u >> v;的话会超时! 
                u = findFather(u);
                v = findFather(v);
                if(u != v){
                    father[v] = u;
                    cnt[u] += cnt[v];
                }
                ans = max(ans, cnt[u]);
            }
            printf("%d
    ", ans);
        }
        return 0;
    }

    总结:之前了解cin的输入速度比scanf慢,但是在写这题时却忘了,然后线上OJ一直提示超时。(以后记得输入数据量很多时,别用cin、cout!!!结果截图如下:)

     然后,是解题思路的问题,我最开始写的代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int MAX=1e7+2; 
    int father[MAX], cnt[MAX];
    int findFather(int x){
        if(x == father[x]) return x;
        else return father[x];
    }
    int main(){
        int i, n, u, v, num, index;
        while(cin >> n){
            for(i=1; i<MAX; i++){
                cnt[i] = 0;
                father[i] = i;
            }
            num = 0;
            for(i=0; i<n; i++){
                cin >> u >> v;
                num = max(num, max(u, v));
                u = findFather(u);
                v = findFather(v);
                if(u != v) father[v] = u;
            }
            for(i=1; i<=num; i++) cnt[father[i]]++;
            for(i=1; i<=num; i++){
                if(i != father[i]) cnt[father[i]] += cnt[i];
            }
            index = 0;
            for(i=1; i<=num; i++) if(cnt[index] < cnt[i]) index = i;
            printf("%d
    ", cnt[index]);
        }
        return 0;
    }

    过了测试用例,但是线上OJ提示:

    后来想了想,一个很大的问题是,输入的数据是无序的,然后每个i对应的father[i]在之后可能会被改变,而原先以i为根节点的变量却还是记录着i,而不是新的father[i]。并且,在后续统计个数时,也是比较繁琐的~之后就卡在这,一直没有解决。此外,对于输入为0时的情况也没有考虑到!

    再分析AC代码,可以发现更简洁,并且时间开销更少(毕竟少了三个for的遍历!)。简化解题步骤的过程在于思考问题的转变,将统计次数的任务在每次判别并查集的过程进行,一旦进行两个不同并查集的合并,就更新并记录最大值。于是,在输入数据结束后,也得到了答案。

    最后,想强调并查集的压缩路径的代码:

    int findFather(int x){ //这段代码值得细细品味 
        if(x == father[x]) return x;
        else{
            int temp = findFather(father[x]);
            father[x] = temp;
            return temp;
        }
    }

    嗯,这段代码是真的精巧~并且,比起用while循环的那种方式,我更喜欢这种精炼的形式,不仅更不易出错,而且即使是大数据集情况下时间开销也相近。至于为什么这段代码压缩了路径,我的理解是:在找到根节点后,返回时将根节点一同返回给了上层,于是将这条路径上的所有节点都直接指向了根节点,从而达到了压缩搜索路径的目的~在理解了上面的基础上,其实还有更简洁的写法,如下:

    int findFather(int x){ //更简洁的写法 
        if(x != father[x]) father[x] = findFather(father[x]);
        return father[x];
    }
  • 相关阅读:
    博客中引用的概念
    重构博客写作
    做中学之教与学工具箱
    做中学之效率工具箱
    两个月选一本理想教材
    《敏捷革命》读书笔记
    《Java2 实用教程(第五版)》学习指导
    得到.每天听本书
    「2017年教育部-永信至诚产学合作协同育人网络空间安全专业课程教学研讨会」参会总结
    Ditto在教学上的应用
  • 原文地址:https://www.cnblogs.com/heyour/p/12708470.html
Copyright © 2011-2022 走看看