zoukankan      html  css  js  c++  java
  • 并查集

    定义

    并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。
    并查集初始化时是一些单独的的点。如下图。

     点之间发生了关系,于是连成了线。

    一条链的祖宗成为另一条链祖宗的儿子。于是链成了树。

     其实并查集相当于一个庞大的家族,家族里的人有的是亲戚关系。当x脉中的任意一人与y脉中的任意一人是亲戚关系,则这两脉都是亲戚关系。

    基本操作

    1.初始化

    首先定义一个fa数组,初始化就是令数组中每个人的爸爸都是他自己。所以f[1]暂时(这里很重要)表示1的爸爸。当出现这种情况时,它就是这一脉的祖宗。代码如下

    void Initialize()
    {
        for(int i=0;i<n;i++) parent[i]=i;
    }
    

      

    2.查找

    小x想知道自己的祖宗是谁,但他只知道自己的爸爸是谁。于是他问他爸爸“”你是我祖先吗?“”他的爸爸不是他祖宗,所以他爸爸问小x的爷爷,也就是他自己的爸爸说:“”你是我祖先吗?“”小x爷爷也不是,也就继续往上问。如此循环下去(假设这一脉长生不老),直到有一个人的爸爸是是他自己,也就是说他是这一脉的祖先。而用代码有两种写法,分别是递归、循环。在这里我只个人推荐递归写法。

    如果我们要询问1的祖宗(假设是5)我们不得不询问2,3,4,5.这样太慢。每次查找复杂度都是O(n),太慢了!

    所以此代码还有一个路径压缩,到这一步。fa数组就不表示爸爸了。为了方便询问,我们自动把f[2],f[3],f[4]都赋成5。方便后续找祖先。

    int findf(int x)
    {
    	if(fa[x]==x) return x; //自己的爸爸是自己,返回自己的编号
    	return fa[x]=findf(fa[x]); //否则询问自己的爸爸
    }
    

     3.合并

    小x和小y成为了亲戚,于是他们这两脉的成为亲戚关系。但只能有一个祖先。怎们办呢?正当他们焦头烂额的时候,我突发奇想说道:“”可以让x祖先成为y祖先的爸爸,这样不就使你们同属一个集合了吗。“”。x脉表示同意,y祖宗虽然有些不愿意。但看在我的面子上也同意了。而这就是并查集的精髓——集合合并。

    void Union(int x,int y)
    {
    	int fx=findf(x),fy=findf(y); //fx表示x的祖宗,fy表示y的祖宗。 
    	fa[fx]=fy; //令y的祖宗成为x的祖宗,这样不管是x脉还是y脉询问祖宗时都是y的祖宗。 
    }
    

    图示

    注:箭头指向自己的爸爸。

    推荐

    最后推荐一道模板题:洛谷P3367 【模板】并查集

     

  • 相关阅读:
    linux 打包 压缩
    HDU 2036 改革春风吹满地
    Windows 7 蓝屏代码大全 &amp; 蓝屏全攻略
    Linux Shell參数扩展(Parameter Expansion)
    android不是内部或外部命令,也不是可执行的程序或批处理文件
    Object类
    抽象类中注意事项
    抽象类和接口的区别
    类接口之间的关系
    接口
  • 原文地址:https://www.cnblogs.com/zxjhaha/p/11207928.html
Copyright © 2011-2022 走看看