zoukankan      html  css  js  c++  java
  • POJ--1988 Cube Stacking(并查集)两种解法

        地址:http://poj.org/problem?id=1988

    Description

    Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes labeled 1 through N. They start with N stacks, each containing a single cube. Farmer John asks Betsy to perform P (1<= P <= 100,000) operation. There are two types of operations: 
    moves and counts. 
    * In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y. 
    * In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value. 

    Write a program that can verify the results of the game. 

    Input

    * Line 1: A single integer, P 

    * Lines 2..P+1: Each of these lines describes a legal operation. Line 2 describes the first operation, etc. Each line begins with a 'M' for a move operation or a 'C' for a count operation. For move operations, the line also contains two integers: X and Y.For count operations, the line also contains a single integer: X. 

    Note that the value for N does not appear in the input file. No move operation will request a move a stack onto itself. 

    Output

    Print the output from each of the count operations in the same order as the input file. 

    Sample Input

    6
    M 1 6
    C 1
    M 2 4
    M 2 6
    C 3
    C 4
    

    Sample Output

    1
    0
    2
        
        题意:n个操作。M x y 表示将x所在的那堆箱子放在y那堆箱子头上。C x 询问x下面有多少箱子。
       解析一:以deep[x]记录x上面有多少箱子,堆顶为根,以all[x]记录x所在堆有多少个箱子。初始化为deep[]=0,all[]=1,pr[i]=i。find()函数的更新过程(包含路径压缩)
    int find(int x)
    {
        if(pr[x]==x)return x;
        int mid=pr[x];
        pr[x]=find(pr[x]);//路径压缩
        deep[x]+=deep[mid]; //下图记录此步
        return pr[x];
    }

        分析过程:

         接下来是join():

    void join(int a,int b)
    {
        int fa=find(a),fb=find(b);
        if(fa!=fb)
        {
            pr[fb]=fa;//以堆顶为根,a放在了b的头上
            deep[fb]+=all[fa];//下图分析此过程
            all[fa]+=all[fb];//下图分析此过程
        }
        return ;
    }

         分析过程:

         计算当前点下面有多少个箱子,就是:all[find(x)]-deep[x]-1

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn=3e5+50;
    int n;
    int pr[maxn],deep[maxn],all[maxn];
    void init()
    {
        for(int i=1;i<=n;i++)
        {
            pr[i]=i;
            deep[i]=0;
            all[i]=1;
        }
    }
    int find(int x)
    {
        if(pr[x]==x)return x;
        int mid=pr[x];
        pr[x]=find(pr[x]);
        deep[x]+=deep[mid];
        return pr[x];
    }
    void join(int a,int b)
    {
        int fa=find(a),fb=find(b);
        if(fa!=fb)
        {
            pr[fb]=fa;
            deep[fb]+=all[fa];
            all[fa]+=all[fb];
        }
        return ;
    }
    int main()
    {
        while(~scanf("%d",&n))
        {
            init();
            char ch;
            int mid=n;
            while(mid--)
            {
                scanf(" %c",&ch);
                if(ch=='M')
                {
                    int a,b;
                    scanf("%d%d",&a,&b);
                    join(a,b);
                }
                else
                {
                    int x;
                    scanf("%d",&x);
                    cout<<all[find(x)]-deep[x]-1<<endl;
                }
            }
        }
    }

        解析二:以deep[x]记录x下面有多少箱子,堆底为根。其他与上面基本相同。find()相同。不同的是join()谁接谁改了一下:

    void join(int a,int b)
    {
        int fa=find(a),fb=find(b);
        if(fa!=fb)
        {
            pr[fa]=fb;//堆底为根。
            deep[fa]+=all[fb];//与上面不同
            all[fb]+=all[fa];//与上面不同
        }
        return ;
    }

        询问x,那么find(x)一下,防止之前没更新,直接输出deep[x]即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn=3e5+50;
    int n;
    int pr[maxn],deep[maxn],all[maxn];
    void init()
    {
        for(int i=1;i<=n;i++)
        {
            pr[i]=i;
            deep[i]=0;
            all[i]=1;
        }
    }
    int find(int x)
    {
        if(pr[x]==x)return x;
        int mid=pr[x];
        pr[x]=find(pr[x]);
        deep[x]+=deep[mid];
        return pr[x];
    }
    void join(int a,int b)
    {
        int fa=find(a),fb=find(b);
        if(fa!=fb)
        {
            pr[fa]=fb;
            deep[fa]+=all[fb];
            all[fb]+=all[fa];
        }
        return ;
    }
    int main()
    {
        while(~scanf("%d",&n))
        {
            init();
            char ch;
            int mid=n;
            while(mid--)
            {
                scanf(" %c",&ch);
                if(ch=='M')
                {
                    int a,b;
                    scanf("%d%d",&a,&b);
                    join(a,b);
                }
                else
                {
                    int x;
                    scanf("%d",&x);
                    find(x);
                    cout<<deep[x]<<endl;
                }
            }
        }
    }
  • 相关阅读:
    C++ 虚函数表解析
    C#编写简单的聊天程序
    c#事件与委托
    c#文本控件实现换行
    docker 详细安装及问题排查
    hadoop命令行
    Spark中的多线程并发处理
    CDH6.1.0离线安装——笔记
    linux 常用命令
    Rsync 恢复 libselinux.SO.1
  • 原文地址:https://www.cnblogs.com/liyexin/p/12627267.html
Copyright © 2011-2022 走看看