zoukankan      html  css  js  c++  java
  • HDU 2473 JunkMail Filter(并查集)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=2473

    题意:有0到n-1个数,M a b  表示a和b合并,S a表示删除a,删除以后a变成独立的集合。。。最后问共有几个集合。。。。

    开始做的时候是真的按步就搬地把a删除,然后把他儿子和他老爸都合起来。。。结果超时。。。。

    还有吧本来是int 型的a,b写成了 char型导致一直溢出,找了很久才找到。。。

    这里用了代理index[i]表示i的代理是index[i],然后以后操作的时候每个人干活只找代理干,然后删除的时候直接换个新代理(这个代理不能和别人的代理冲突,开始的时候是独立的集合),

    然后他原来的代理事实上还在本来那里,没有删除,因为我们只找代理来干活,而他原来的代理已经不是代理了,所以不会找到原来那个代理。。。。。

    最后统计的时候,正常来说我们可以扫一遍代理,看father[代理] == 代理就累加,而这里不正常,会计少了集合的。。。。。

    因为当你删除的代理是根,而该树的儿子孙子还有别人的代理,即该集合也算一个集合,当你最后找的时候,因为只找代理,而那些算一个集合的,而根本来是代理,因为删除后而不是代理了的集合就会没有统计。。。。

    所以我们扫所有代理用Find()来找根,然后用标记法(因为可能多个代理同一个根)来把根标记,最后统计根的个数

    #include <iostream>
    using namespace std;
    
    const  int M = 10000100;
    
    int father[M];
    int rank1[M];
    int save[M];
    int index[M];
    bool used[M];
    
    
    void Make_Set(int x)
    {
        father[x] = x;
        rank1[x] = 0;
    }
    
    int Find(int x)
    {
        int k = 0;
        while (x != father[x])
        {
            save[k++] = x;
            x = father[x];
        }
    
        for (int j = 0; j < k; j++)
        {
            father[save[j]] = x;
        }
        return x;
    }
    
    
    void Union(int a, int b)
    {
    
        int x = Find(a);
        int y = Find(b);
        
        if (x == y)
        {
            return;
        }
        if (rank1[x] < rank1[y])
        {
            father[x] = y;
        }
        else
        {
            father[y] = x;
            if (rank1[x] == rank1[y])
            {
                rank1[x]++;
            }
        }
    }
    
    
    
    int main()
    {
        int n, m;
        int case1 = 0;
        while (~scanf("%d%d", &n, &m), n + m)
        {
            
            for (int i = 0; i < n; i++)
            {
                Make_Set(i);
                index[i] = i;//开始代理都是本身
            }
    
            int k = n+1;
            while (m--)
            {
                char str[10];
                int a, b;
                scanf("%s", str);
                if (str[0] == 'M')
                {
                    scanf("%d%d", &a, &b);
                    Union(index[a], index[b]);
                }
                else
                {
                    scanf("%d", &a);
                    index[a] = k++;//换代理
                    Make_Set(index[a]);
                }
    
            }
    
            int count = 0;
            memset(used, 0, sizeof(used));
            for (int  i = 0; i < n; i++)
            {
                //if (father[i] == i)或father[index[i]] == index[i] 都是错的
                //{
                //    count++;
                //}
                used[Find(index[i])] = 1;//标记根
            }
    
            for (int i = 0; i < k; i++)
            {
                if (used[i])
                {
                    count++;
                }
            }
    
            printf("Case #%d: %d\n", ++case1, count);
        }
        return 0;
    }
  • 相关阅读:
    在我的S5pv210开发板上安装busybox并体验busybox devmem 命令的强大功能
    修改 android 的 framework 层操作小记.转载
    【原创】再次强调MLC Nandflash 6410 开发板的不稳定性带来的安全隐患问题
    转载.简要介绍android HAL JNI HAL的基础
    【转】Andriod关机&重启分析
    转载.程序员为什么地位不高?
    转载.android 对linux 内核的改动,到底改了多少?
    在Ubuntu上为Android系统编写Linux内核驱动程序
    修改android HDMI 输出默认分辨率的方法
    [转载]Android编译过程详解(三)
  • 原文地址:https://www.cnblogs.com/qiufeihai/p/2668244.html
Copyright © 2011-2022 走看看