zoukankan      html  css  js  c++  java
  • 并查集——poj1988(带权并查集中等)

    一、题目回顾

    题目链接:Cube Stacking

    题意:有n个箱子,初始时每个箱子单独为一列;接下来有p行输入,M, x, y 或者 C, x;

    • 对于M,x,y:表示将x箱子所在的一列箱子搬到y所在的一列箱子上;
    • 对于C,x:表示求箱子x下面有多少个箱子;

    输出:在箱子x所在的那列中,求出在x之下的cube的个数。

    二、解题分析

    知识点:带权并查集

    解题思路

    • 初级:M x y是将x所在列的所有箱子叠到y所在列的上面,如果直接模拟的话就是将x最末端的叶子节点当做y的根节点的父亲节点合并,不过那样的话不好压缩路径,不压缩路径的话会超时.......
    • 高级:用数组s存储当前节点x的子结点数量,用数组d存储当前节点到根节点的距离,所求值即s[find(x)]-d[x],(也许你会说要求的不就是s[x]吗,道理是这样,但我们并没有求出每个节点的子结点数量
    • 续上高级:按照一般并查集的合并方法,令pre[find(y)]=find(x);那合并后会有: d[find(y)]=s[find(x)]+1,s[find(x)]+=s[find(y)]+1 。(不清楚可以自己在草稿纸上画图确定)

    重要之处

    • 多了两个结点之间的关系
    1. d[x]表示结点x到根的距离
    2. s[x]表示在结点x下cube的数量
    • 然后在find函数、unite函数内维持这两个数组即可

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int p;
    int pre[30005];
    int d[30005];        //d[x]表示结点x到根的距离
    int s[30005];        //s[x]表示在结点x下cube的数量 
    void init()
    {
        for(int i=1;i<=30005;i++){
            pre[i] = i;
    //        d[i] = 0;            加上这个就 WA 
            s[i] = 0;
        }
    }
    
    int find(int x)
    {
        if(x==pre[x])    return x;
        int t = pre[x];                //***递归思想,t为存储x改变根节点后的根节点的临时变量
        pre[x] = find(pre[x]);
        d[x] = d[x] + d[t];             //***x到改变前根节点的距离即x到t的距离加上t到根节点的距离
        return pre[x];
    }
    
    void unite(int x,int y)
    {
        int fx = find(x);
        int fy = find(y);
        if(fx != fy){
            pre[fy] = fx;
            //***将x所在列放到y所在列上面后,find(y)到新合并后的根节点的距离即为合并前find(x)的子树的大小
            d[fy] = s[fx]+1;        
            s[fx] = s[fx]+(s[fy]+1);    //***合并后find(x)的子树大小即为合并前find(x)与find(y)的子树大小的和
        }
    }
    
    int main()
    {
    
         cin>>p;
        init();
        char ch; int x,y;
        getchar();
        while(p--){
            scanf("%c",&ch);
            if(ch=='M'){
                scanf("%d%d",&x,&y);
                unite(x,y);
            }
            if(ch=='C'){
                scanf("%d",&x);
                //***注意这里并不是输出son(x),因为我们并没有求出每个节点的子树的大小
                printf("%d
    ",s[find(x)]-d[x]);
            }
            getchar(); 
        }
        return 0;
    }
  • 相关阅读:
    linux unzip
    ASP.NetViewState的实现方案
    周鸿袆:从程序员创业谈起
    程序员不是神,心态决定一切
    35岁以前成功的12条黄金法则
    Web的系统测试方法 (转载)
    Assembly反射机制错误解决之道
    利用ViewState保存Html控件状态
    触发器与@@IDENTITY的
    基于SQL Server 2005新特性的分页存储过程
  • 原文地址:https://www.cnblogs.com/xzxl/p/7344374.html
Copyright © 2011-2022 走看看