• (待整理)B


    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
    

    本思路简单,但是没有路径压缩和优化,因此虽然结果正确,但是会超时,到现在也没想出怎样进行路径压缩

    就是用数组记录下父节点和子节点,从而形成一个没有树枝的树,但是这样最大的坏处就是在遍历时会消耗大量的时间,不可取。

    #include<iostream>
    #include <cstdio>
    using namespace std;
    int count ;
    int son[30005],fa[30005];
    int find(int w)
    {
     if(fa[w]==0)
      return w;
     else
     {
      count++;
     return   find(fa[w]);
     }
    }
    int findson(int w)
    {
     if(son[w]==0)
      return w;
      else
      findson(son[w]);
    }
    int main()
    {
     int  n,i,x,y,w;
     scanf("%d",&n); 
     memset(son,0,4*30005);
        memset(fa,0,4*30005);
     for(i=1;i<=n;i++)
     {
      count=0;
      char ch;
      getchar();
      scanf("%c",&ch);
      if(ch=='M')
      {
       scanf("%d%d",&x,&y);
       x=find(x);
       y=findson(y);
       fa[x]=y;
       son[y]=x;
      }
      else
      {
       scanf("%d",&w);
       find(w);
       printf("%d ",count);
      }  
     }
     return 0;
    }

    思路稍做优化,依旧超时.........但是结果依旧是正确的

    #include<iostream>
    #include <cstdio>
    using namespace std;
    int son[30005],fa[30005],count[30005];
    int findfa(int x,int y)
    {
     if(fa[x]==0)
     {
      count[x]=count[x]+count[y];
      return x;
     }
     else
     {
        count[x]=count[x]+count[y];
     return   findfa(fa[x],y);
     }
    }
    int findson(int w)
    {
     if(son[w]==0)
      return w;
      else
      findson(son[w]);
    }
    void Count(int x,int cou )
    {
     count[x]=cou+count[x];
     if(son[x]==0)
      return ;
     Count(son[x],cou);
    }
    int main()
    {
     int  n,i,x,y,w;
     scanf("%d",&n); 
     memset(son,0,4*30005);
        memset(fa,0,4*30005);
        for( i=0;i<30005;i++)
      count[i]=1;
     for(i=1;i<=n;i++)
     {
      char ch;
      getchar();
      scanf("%c",&ch);
      if(ch=='M')
      {
       scanf("%d%d",&x,&y);
       y=findson(y);
       Count(x,count[y]);
       x=findfa(x,y);
      // cout<<"****************"<<x<<' '<<y<<endl;
       fa[x]=y;
       son[y]=x;
      }
      else
      {
       scanf("%d",&w);
       printf("%d ",count[w]-1) ;
      }  
     }
     return 0;
    }

    正解:

    #include<cstdio>
    #include<cstring>
    const int maxn=100000+5;
    int set[maxn],cnt[maxn],top[maxn];  //t[k]为k所在栈的栈底元素序号,top[k]为k所在栈的栈顶元素序号,cnt[k]为k到set[k]的元素个数
    int set_find(int p)                     //计算元素p所在栈的栈底元素set[p]以及p到set[p]的元素个数,路径压缩
    {
        if(set[p]<0)                   //栈中只有一个元素p
            return p;
        if(set[set[p]]>=0)              //的下方还有元素
        {
            int fa=set[p];
            set[p]=set_find(fa);
            cnt[p]=cnt[p]+cnt[fa];       //累加从fa到set[p]之间的元素个数,计算出每个元素到栈底的距离
        }
        return set[p];
    }
    void set_join(int x,int y)          //将x所在的栈移动到y所在的栈的栈顶
    {
        x=set_find(x);                //将x,y分别设置为相应栈的栈底元素的序号
        y=set_find(y);i
        set[x]=y;                     //将y设置为set[x]的下一元素,两个栈连接完成
        set_find(top[y]);            //计算原先y所在栈的栈顶元素到栈底元素之间的元素个数
        cnt[x]=cnt[top[y]]+1;        //计算新栈从x到栈底的元素个数
        top[y]=top[x];               //更新y所在栈的栈顶元素为x原来所在栈的栈顶元素
    }
    int main()
    {
        int p;
        scanf("%d",&p);              //输入操作的数目
        memset(set,-1,sizeof(set));  //将set中所有的元素都独自成栈
        memset(cnt,0,sizeof(cnt));   //清空计数
        for(int i=0; i<maxn; i++)    //初始化每一个栈的栈顶元素
            top[i]=i;
        while(p--)
        {
            char s[5];
            scanf("%s",s);               //读入当前操作
            if(s[0]=='M') 
            {
                int x,y;
                scanf("%d%d",&x,&y);   
                set_join(x,y);          //移动栈
            }
            else
            {
                int x;
                scanf("%d",&x);
                set_find(x);
                printf("%d ",cnt[x]);
            }
        }
        return 0;
    }

  • 相关阅读:
    实例!使用Idea创建SSM框架的Maven项目
    springboot开发中的领域模型pojo
    JDK源码阅读:Object类阅读笔记
    DevSecOps: JIRA、Confluence工具、JIRA插件-Xray、eazybi、FishEye、Crucible、jenkins
    MySQL监控及优化
    二叉树 红黑树 B树 B+树 理解
    mysql高性能分页语句_如何优化Mysql千万级快速分页
    使用.Net MinIO SDK 踩的坑
    Windows下Minio介绍、安装及使用、密码修改
    使用docker mediawiki,搭建网页wiki
  • 原文地址:https://www.cnblogs.com/zswbky/p/5432112.html
Copyright © 2020-2023  润新知