并查集

来源:互联网 发布:centos安装配置ftp 编辑:程序博客网 时间:2024/05/26 19:17


【1024程序员节】参加活动领暖心礼品     【观点】有了深度学习,你还学传统机器学习算法么?     【知识库】深度学习知识图谱上线啦
 

[置顶] 并查集详解 (转)

标签: join算法电话编程优化
 49737人阅读 评论(79) 收藏 举报
 分类:

这个文章是几年前水acm的时候转的, 当时也不知道作者是谁, 要是有人知道的话说一下吧


并查集是我暑假从高手那里学到的一招,觉得真是太精妙的设计了。以前我无法解决的一类问题竟然可以用如此简单高效的方法搞定。不分享出来真是对不起party了。(party:我靠,关我嘛事啊?我跟你很熟么?)

来看一个实例,杭电1232畅通工程

首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题。比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块。像畅通工程这题,问还需要修几条路,实质就是求有几个连通分支。如果是1个连通分支,说明整幅图上的点都连起来了,不用再修路了;如果是2个连通分支,则只要再修1条路,从两个分支中各选一个点,把它们连起来,那么所有的点都是连起来的了;如果是3个连通分支,则只要再修两条路……

以下面这组数据输入数据来说明

4 2 1 3 4 3

第一行告诉你,一共有4个点,2条路。下面两行告诉你,1、3之间有条路,4、3之间有条路。那么整幅图就被分成了1-3-4和2两部分。只要再加一条路,把2和其他任意一个点连起来,畅通工程就实现了,那么这个这组数据的输出结果就是1。好了,现在编程实现这个功能吧,城镇有几百个,路有不知道多少条,而且可能有回路。 这可如何是好?

我以前也不会呀,自从用了并查集之后,嗨,效果还真好!我们全家都用它!

并查集由一个整数型的数组和两个函数构成。数组pre[]记录了每个点的前导点是什么,函数find是查找,join是合并。

int pre[1000 ];

int find(int x)                                                                                                         //查找根节点

    int r=x;

    while ( pre[r ] != r )                                                                                              //返回根节点 r

          r=pre[r ];

 

    int i=x , j ;

    while( i != r )                                                                                                        //路径压缩

    {

         j = pre[ i ]; // 在改变上级之前用临时变量  j 记录下他的值 

         pre[ i ]= r ; //把上级改为根节点

         i=j;

    }

    return r ;

}

 

 

void join(int x,int y)                                                                                                    //判断x y是否连通,

                                                                                             //如果已经连通,就不用管了 //如果不连通,就把它们所在的连通分支合并起,

{

    int fx=find(x),fy=find(y);

    if(fx!=fy)

        pre[fx ]=fy;

}

 

为了解释并查集的原理,我将举一个更有爱的例子。 话说江湖上散落着各式各样的大侠,有上千个之多。他们没有什么正当职业,整天背着剑在外面走来走去,碰到和自己不是一路人的,就免不了要打一架。但大侠们有一个优点就是讲义气,绝对不打自己的朋友。而且他们信奉“朋友的朋友就是我的朋友”,只要是能通过朋友关系串联起来的,不管拐了多少个弯,都认为是自己人。这样一来,江湖上就形成了一个一个的群落,通过两两之间的朋友关系串联起来。而不在同一个群落的人,无论如何都无法通过朋友关系连起来,于是就可以放心往死了打。但是两个原本互不相识的人,如何判断是否属于一个朋友圈呢?

我们可以在每个朋友圈内推举出一个比较有名望的人,作为该圈子的代表人物,这样,每个圈子就可以这样命名“齐达内朋友之队”“罗纳尔多朋友之队”……两人只要互相对一下自己的队长是不是同一个人,就可以确定敌友关系了。

但是还有问题啊,大侠们只知道自己直接的朋友是谁,很多人压根就不认识队长,要判断自己的队长是谁,只能漫无目的的通过朋友的朋友关系问下去:“你是不是队长?你是不是队长?”这样一来,队长面子上挂不住了,而且效率太低,还有可能陷入无限循环中。于是队长下令,重新组队。队内所有人实行分等级制度,形成树状结构,我队长就是根节点,下面分别是二级队员、三级队员。每个人只要记住自己的上级是谁就行了。遇到判断敌友的时候,只要一层层向上问,直到最高层,就可以在短时间内确定队长是谁了。由于我们关心的只是两个人之间是否连通,至于他们是如何连通的,以及每个圈子内部的结构是怎样的,甚至队长是谁,并不重要。所以我们可以放任队长随意重新组队,只要不搞错敌友关系就好了。于是,门派产生了。

http://i3.6.cn/cvbnm/6f/ec/f4/1e9cfcd3def64d26ed1a49d72c1f6db9.jpg


下面我们来看并查集的实现。 int pre[1000]; 这个数组,记录了每个大侠的上级是谁。大侠们从1或者0开始编号(依据题意而定),pre[15]=3就表示15号大侠的上级是3号大侠。如果一个人的上级就是他自己,那说明他就是掌门人了,查找到此为止。也有孤家寡人自成一派的,比如欧阳锋,那么他的上级就是他自己。每个人都只认自己的上级。比如胡青牛同学只知道自己的上级是杨左使。张无忌是谁?不认识!要想知道自己的掌门是谁,只能一级级查上去。 find这个函数就是找掌门用的,意义再清楚不过了(路径压缩算法先不论,后面再说)。

int find(int x)                                                                  //查找我(x)的掌门

{

    int r=x;                                                                       //委托 r 去找掌门

    while (pre[r ]!=r)                                                        //如果r的上级不是r自己(也就是说找到的大侠他不是掌门 = =)

    r=pre[r ] ;                                                                   // r 就接着找他的上级,直到找到掌门为止。

    return  r ;                                                                   //掌门驾到~~~

}

再来看看join函数,就是在两个点之间连一条线,这样一来,原先它们所在的两个板块的所有点就都可以互通了。这在图上很好办,画条线就行了。但我们现在是用并查集来描述武林中的状况的,一共只有一个pre[]数组,该如何实现呢? 还是举江湖的例子,假设现在武林中的形势如图所示。虚竹小和尚与周芷若MM是我非常喜欢的两个人物,他们的终极boss分别是玄慈方丈和灭绝师太,那明显就是两个阵营了。我不希望他们互相打架,就对他俩说:“你们两位拉拉勾,做好朋友吧。”他们看在我的面子上,同意了。这一同意可非同小可,整个少林和峨眉派的人就不能打架了。这么重大的变化,可如何实现呀,要改动多少地方?其实非常简单,我对玄慈方丈说:“大师,麻烦你把你的上级改为灭绝师太吧。这样一来,两派原先的所有人员的终极boss都是师太,那还打个球啊!反正我们关心的只是连通性,门派内部的结构不要紧的。”玄慈一听肯定火大了:“我靠,凭什么是我变成她手下呀,怎么不反过来?我抗议!”抗议无效,上天安排的,最大。反正谁加入谁效果是一样的,我就随手指定了一个。这段函数的意思很明白了吧?

void join(int x,int y)                                                                   //我想让虚竹和周芷若做朋友

{

    int fx=find(x),fy=find(y);                                                       //虚竹的老大是玄慈,芷若MM的老大是灭绝

    if(fx!=fy)                                                                               //玄慈和灭绝显然不是同一个人

    pre[fx ]=fy;                                                                           //方丈只好委委屈屈地当了师太的手下啦

}

再来看看路径压缩算法。建立门派的过程是用join函数两个人两个人地连接起来的,谁当谁的手下完全随机。最后的树状结构会变成什么胎唇样,我也完全无法预计,一字长蛇阵也有可能。这样查找的效率就会比较低下。最理想的情况就是所有人的直接上级都是掌门,一共就两级结构,只要找一次就找到掌门了。哪怕不能完全做到,也最好尽量接近。这样就产生了路径压缩算法。 设想这样一个场景:两个互不相识的大侠碰面了,想知道能不能揍。 于是赶紧打电话问自己的上级:“你是不是掌门?” 上级说:“我不是呀,我的上级是谁谁谁,你问问他看看。” 一路问下去,原来两人的最终boss都是东厂曹公公。 “哎呀呀,原来是记己人,西礼西礼,在下三营六组白面葫芦娃!” “幸会幸会,在下九营十八组仙子狗尾巴花!” 两人高高兴兴地手拉手喝酒去了。 “等等等等,两位同学请留步,还有事情没完成呢!”我叫住他俩。 “哦,对了,还要做路径压缩。”两人醒悟。 白面葫芦娃打电话给他的上级六组长:“组长啊,我查过了,其习偶们的掌门是曹公公。不如偶们一起及接拜在曹公公手下吧,省得级别太低,以后查找掌门麻环。” “唔,有道理。” 白面葫芦娃接着打电话给刚才拜访过的三营长……仙子狗尾巴花也做了同样的事情。 这样,查询中所有涉及到的人物都聚集在曹公公的直接领导下。每次查询都做了优化处理,所以整个门派树的层数都会维持在比较低的水平上。路径压缩的代码,看得懂很好,看不懂也没关系,直接抄上用就行了。总之它所实现的功能就是这么个意思。

http://i3.6.cn/cvbnm/60/98/92/745b3eac68181e4ee1fa8d1b8bca38bc.jpg


 

 

hdu1232

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include<iostream>  
  2. using namespace std;  
  3.   
  4. int  pre[1050];  
  5. bool t[1050];               //t 用于标记独立块的根结点  
  6.   
  7. int Find(int x)  
  8. {  
  9.     int r=x;  
  10.     while(r!=pre[r])  
  11.         r=pre[r];  
  12.       
  13.     int i=x,j;  
  14.     while(pre[i]!=r)  
  15.     {  
  16.         j=pre[i];  
  17.         pre[i]=r;  
  18.         i=j;  
  19.     }  
  20.     return r;  
  21. }  
  22.   
  23. void mix(int x,int y)  
  24. {  
  25.     int fx=Find(x),fy=Find(y);  
  26.     if(fx!=fy)  
  27.     {  
  28.         pre[fy]=fx;  
  29.     }  
  30. }   
  31.   
  32. int main()  
  33. {  
  34.     int N,M,a,b,i,j,ans;  
  35.     while(scanf("%d%d",&N,&M)&&N)  
  36.     {  
  37.         for(i=1;i<=N;i++)          //初始化   
  38.             pre[i]=i;  
  39.           
  40.         for(i=1;i<=M;i++)          //吸收并整理数据   
  41.         {  
  42.             scanf("%d%d",&a,&b);  
  43.             mix(a,b);  
  44.         }  
  45.           
  46.           
  47.         memset(t,0,sizeof(t));  
  48.         for(i=1;i<=N;i++)          //标记根结点  
  49.         {  
  50.             t[Find(i)]=1;  
  51.         }  
  52.         for(ans=0,i=1;i<=N;i++)  
  53.             if(t[i])  
  54.                 ans++;  
  55.                   
  56.         printf("%d\n",ans-1);  
  57.           
  58.     }  
  59.     return 0;  
  60. }//dellaserss  


以下为原文附的代码:

 

回到开头提出的问题,我的代码如下:

#include int pre[1000 ];

int find(int x)

{

    int r=x;

   while (pre[r ]!=r)

   r=pre[r ];

   int i=x; int j;

   while(i!=r)

   {

       j=pre[i ];

       pre[i ]=r;

       i=j;

   }

   return r;

}

int main()

{

   int n,m,p1,p2,i,total,f1,f2;

   while(scanf("%d",&n) && n)         //读入n,如果n为0,结束

   {                                                    //刚开始的时候,有n个城镇,一条路都没有 //那么要修n-1条路才能把它们连起来

       total=n-1;

       //每个点互相独立,自成一个集合,从1编号到n //所以每个点的上级都是自己

       for(i=1;i<=n;i++) { pre[i ]=i; }                //共有m条路

       scanf("%d",&m); while(m--)

       { //下面这段代码,其实就是join函数,只是稍作改动以适应题目要求

           //每读入一条路,看它的端点p1,p2是否已经在一个连通分支里了

           scanf("%d %d",&p1,&p2);

           f1=find(p1);

           f2=find(p2);

               //如果是不连通的,那么把这两个分支连起来

               //分支的总数就减少了1,还需建的路也就减了1

           if(f1!=f2)

            {

               pre[f2 ]=f1;

               total--;

           }

           //如果两点已经连通了,那么这条路只是在图上增加了一个环 //对连通性没有任何影响,无视掉

       }

//最后输出还要修的路条数

       printf("%d\n",total);

   }

   return 0;

}

 

96
0
 
 

我的同类文章

  • hdu3555 数位dp入门题2013-05-09
  • poj1741Tree 树的分治 树形dp 男人八题....2013-04-26
  • hdu2196Computer 经典树形dp 在树上求最长距离2013-04-18
  • POJ1947 树形dp 重做2013-04-16
  • poj1155TELE - 树形dp2013-04-15
  • hdu3535 01&分组背包2013-04-11
  • poj3107 树的重心 非stl实现2013-05-06
  • poj1655Balancing Act 树的重心,树形dp2013-04-23
  • hdu1520 Anniversary party 树形dp2013-04-18
  • hdu1011Starship Troopers 树形DP2013-04-15
  • hdu1561树形DP入门2013-04-14
更多文章

参考知识库

img

算法与数据结构知识库

猜你在找
数据结构和算法
数据结构基础系列(1):数据结构和算法
以性别预测为例,谈谈数据挖掘中常见的分类算法
模板匹配的字符识别(OCR)算法原理
Python算法实战视频课程--二叉树
并查集详解 转
并查集详解转
并查集详解转
并查集详解 转
并查集详解 转
查看评论
76楼 yongf2014 2016-09-15 21:58发表 [回复]
这个可以有。。。
75楼 cqweimingdan 2016-09-14 08:59发表 [回复]
赞!!
74楼 AnXT 2016-09-05 18:55发表 [回复]
讲的太棒了,赞一个!
73楼 陈小fat 2016-08-27 00:05发表 [回复]
感觉写得好通俗易懂~赞一个,可以转载吗?~
72楼 smileFFFF 2016-08-17 22:04发表 [回复]
一遍就懂~ 学习如此轻松
71楼 yyoc97 2016-08-11 17:30发表 [回复]
受教了!!
70楼 tingyun_say 2016-07-25 11:26发表 [回复]
mark了,听了个故事看懂了一个算法
69楼 项三六 2016-07-25 11:25发表 [回复]
怒评一波,刚刚老师讲得我昏昏欲睡
68楼 Onwaier 2016-07-23 21:29发表 [回复]
真心的不错,从未觉得学习可以轻松。。
67楼 qq_35650561 2016-07-19 20:57发表 [回复]
清晰明了,讲的很详细
66楼 yakoazz 2016-07-11 22:06发表 [回复]
太有趣啦,讲的真好,处女评论,哈哈
65楼 Brave-girl 2016-06-24 15:17发表 [回复]
第一次评论,简直不能再赞!!!
64楼 klc1 2016-06-09 21:17发表 [回复]
楼主这么可爱一定是个妹子!
63楼 澜水 2016-05-17 14:15发表 [回复]
竟然听懂了T^T,赞!!

但是那个路径压缩的链接进不去了,让我在你的代码里再找一圈
62楼 lethalboy 2016-05-10 09:46发表 [回复]
膜拜楼主,讲的好极了
61楼 _涧边幽草 2016-05-03 22:01发表 [回复]
谢谢
60楼 Puyar_ 2016-05-01 18:39发表 [回复]
楼主自己贴的那个代码过不了的。。。。
59楼 zha0zha0zha 2016-04-27 21:51发表 [回复]
这个必须赞
58楼 Lee_Handsome 2016-04-19 19:44发表 [回复]
真心6,讲得好
57楼 chen_hongdong 2016-04-16 21:52发表 [回复]
讲得真好
56楼 imGala 2016-03-23 16:26发表 [回复]
讲得太好了,头次见到这么有意思的算法博客,赞个
55楼 tudou_0 2016-03-18 12:05发表 [回复]
赞一个
54楼 oney_hu 2016-03-08 09:39发表 [回复]
Mark
53楼 sxy_799 2016-02-29 22:08发表 [回复]
太有才了
52楼 qq_28859199 2016-02-20 10:07发表 [回复]
讲得好,妈妈再也不用担心我用打火机了
51楼 lemonoil 2016-01-26 16:32发表 [回复]
第一次评论,真心可以
50楼 qq_33688788 2016-01-09 19:24发表 [回复]
真棒!我自己看课件看了老半天看得快睡着了,看完这篇文章一下子就明白了!
49楼 少年呀 2015-12-04 17:48发表 [回复]
虽然是转的,但还是要给你赞
48楼 EatAppleS 2015-11-27 15:22发表 [回复]
感觉和two-path连通域搜索,挺像的
47楼 bwju 2015-11-26 12:18发表 [回复]
我的第一次评论,原创作者真是太厉害了
46楼 ljlstart 2015-10-08 21:16发表 [回复]
赞!!!!!!!!!!1
45楼 qq8871647 2015-09-27 15:54发表 [回复]
十分感谢
44楼 wahaha111111111 2015-09-20 16:01发表 [回复]
天呐,真的只要一遍!!!!!!1
43楼 CourageK 2015-09-17 19:45发表 [回复]
之前一直听我身边的同学提起并查集,他们讲得口若悬河,但是我一直不太明白。今天趁着在复习数据结构的机会,学习了这篇博客,觉得很浅显易懂,谢谢你~
42楼 youhebuke52011 2015-09-14 21:57发表 [回复]
6666666666
41楼 vcmfsmsrm 2015-09-10 16:31发表 [回复]
好文章~~有意思
40楼 NemoEvertt 2015-09-08 18:33发表 [回复]
mark
39楼 huangkailnn 2015-09-01 15:06发表 [回复]
非常好的文章
38楼 baidu_30779555 2015-08-22 18:23发表 [回复]
感谢楼主 并查集 一下就懂了
37楼 fsafdsafsa 2015-08-19 15:24发表 [回复]
真不错!
36楼 sunshine_YG 2015-08-10 22:31发表 [回复]
nice
35楼 justry24 2015-08-10 17:20发表 [回复]
听君一席话,胜看俩小时书!
34楼 yin19930412 2015-08-03 15:43发表 [回复]
楼主我觉得我快要爱上你了,讲的不能再赞
33楼 qq_30233451 2015-07-30 14:52发表 [回复]
妈的,写的太好了,一看即懂,妈妈再也不用担心我的学习
32楼 coderhzx 2015-07-30 13:26发表 [回复]
欢乐的讲解o(∩_∩)o ,收藏了
31楼 大个儿柚子 2015-07-29 09:34发表 [回复]
写的太好了。感谢感谢
30楼 liliangwei_sau 2015-07-26 15:38发表 [回复]
写得太好了,十分感谢。
29楼 gxfcome 2015-07-21 20:30发表 [回复]
写得很有意思
28楼 ZeroMem_0 2015-07-20 18:49发表 [回复]
有一个问题没想明白。
路径应该是双向的比如数据里面有一行是(3,7)就是说pre[3] = 7, pre[7] = 3.但是博主这个好像没体现出来
Re: ZeroMem_0 2015-07-20 19:02发表 [回复]
回复ZeroMem_0:刚才自己画图试了一下,即使是双向的,检查连同性的时候是不会出问题的。看来是一开是没弄清出并查集的应用背景。
27楼 zju兔子哥哥 2015-07-20 15:34发表 [回复]
66666
26楼 qq_21042919 2015-07-14 19:54发表 [回复]
学习了2333
25楼 chengchaoli 2015-06-28 14:58发表 [回复]
玄慈做了灭绝的手下。。写的真好
24楼 sinat_29166571 2015-06-19 20:22发表 [回复]
写的已经不能再棒
23楼 技术宅--火狼 2015-06-17 18:40发表 [回复]
楼主,太可爱了,举的例子萌萌哒啊!一看就懂啊!!
22楼 ningai007 2015-06-15 10:23发表 [回复]
讲解的很明白,真心喜欢~~~
21楼 holly_green 2015-06-06 15:45发表 [回复]
这样要求连通子图的边的输入是以一种顺序的遍历的输入,对于一些乱序输入的题目无法压缩
20楼 sxxymzy 2015-05-28 20:17发表 [回复]
从来没评论过,但是这篇写得太棒了,点赞!!
19楼 dangeroushai 2015-05-26 11:22发表 [回复]
受教,谢过!
18楼 chenchukun 2015-05-21 22:16发表 [回复]
写得真好,之前一直不是很明白,现在懂了,谢谢。
17楼 yang1018679 2015-05-13 11:07发表 [回复]
简单易懂,还有趣。
16楼 牛炖 2015-05-12 17:46发表 [回复]
看乐了,瞬间明白
15楼 _天道酬勤_不忘初心 2015-04-24 20:43发表 [回复]
HDU 1232不用标记根节点,直接 for(i=1;i<=n;i++)
{
if(pre[i]==i)
ans++;
}即可
14楼 杨汉祥 2015-04-22 20:28发表 [回复]
写的真的很nice啊!
13楼 mzzzzq 2015-04-15 15:10发表 [回复]
懂了,多谢
12楼 mzzzzq 2015-04-15 15:09发表 [回复]
要是算法老师都这样形象的讲课,那就好了
11楼 sdauwcy 2015-04-13 22:26发表 [回复]
简单易懂!多谢!
10楼 Ftworld21 2015-04-13 17:40发表 [回复]
以前一直没搞懂这个并查集是什么意思 也看不懂 看了你写的文章后 豁然开朗 多谢大侠分享
9楼 tt2767 2015-03-29 11:40发表 [回复]
路径压缩里面为什么要保留上级的信息,直接覆盖不就好了么?
Re: tt2767 2015-03-29 11:40发表 [回复]
回复tt2767:。。。。看懂了
Re: _天道酬勤_不忘初心 2015-04-24 18:48发表 [回复]
回复tt2767:四弟告诉三弟咱的老大是谁,然后三弟告诉二弟咱的老大是谁,二弟的老大就是老大就不用告诉了
Re: _天道酬勤_不忘初心 2015-04-24 18:47发表 [回复]
回复tt2767:四弟告诉三弟咱的老大是谁,三弟再告诉二弟咱的老大是谁,二弟的老大就是老大就不用告诉了
8楼 茶叶团子 2015-03-27 21:05发表 [回复]
明明是讲算法的,我看乐了
7楼 ProjectDD 2015-03-05 09:48发表 [回复]
写得真好 点赞
6楼 MSJ_CS 2015-02-05 15:52发表 [回复]
好棒,看完居然可以自己写了。。点赞!
5楼 Clarehehe 2015-02-02 10:37发表 [回复]
清晰易懂,受教了
4楼 -releaner- 2015-01-12 17:38发表 [回复]
简单易懂,一看就会~\(≧▽≦)/~
3楼 haoflynet 2013-12-20 18:29发表 [回复]
写得很好,看一遍就懂
2楼 wu0402204 2013-10-24 16:06发表 [回复]
通俗易懂,写的真不错!mack一下!
1楼 NYIST_creat2012 2013-10-23 21:42发表 [回复]
并查集是否有快速查找的用法,比如呢?
发表评论
  • 用 户 名:
  • github_35957188
  • 评论内容:
  • 插入代码
      
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
核心技术类目
全部主题 Hadoop AWS 移动游戏 Java Android iOS Swift 智能硬件 Docker OpenStack VPN Spark ERP IE10Eclipse CRM JavaScript 数据库 Ubuntu NFC WAP jQuery BI HTML5 Spring Apache .NET API HTML SDK IISFedora XML LBS Unity Splashtop UML components Windows Mobile Rails QEMU KDE Cassandra CloudStack FTCcoremail OPhone CouchBase 云计算 iOS6 Rackspace Web App SpringSide Maemo Compuware 大数据 aptech PerlTornado Ruby Hibernate ThinkPHP HBase Pure Solr Angular Cloud Foundry Redis Scala Django Bootstrap
    个人资料
     
    laserss
     
    • 访问:168502次
    • 积分:2666
    • 等级: 
    • 排名:第10113名
    • 原创:125篇
    • 转载:10篇
    • 译文:0篇
    • 评论:96条
    文章分类
  • 最短路(11)
  • 动态规划(29)
  • 母函数(8)
  • 简单题(8)
  • - -(6)
  • zoj(2)
  • pku(25)
  • hdu(75)
  • acm(112)
  • 计算几何(5)
  • 数学(16)
  • 贪心(2)
  • 字典树(4)
  • BST(2)
  • dfs(5)
  • 二分图(2)
  • bfs(6)
  • 模板(15)
  • 博弈(1)
  • hash(1)
  • 字符串(3)
  • 图论~(5)
  • wind(0)
  • windows sdk(3)
  • HLSL(1)
    阅读排行
  • 并查集详解 (转)(49713)
  • hdu2073-无限的路(4266)
  • 程序员装逼指南(4129)
  • hdu,poj 分类(2853)
  • hdu1269 Tarjan强连通分量 模板(2160)
  • hdu1561树形DP入门(1988)
  • hdu2824筛选法欧拉函数+求和(1973)
  • hdu2586 LCA模板(1937)
  • hdu 2059 龟兔赛跑 动态规划(1936)
  • ACM 推荐blog汇总及OJ(1875)
    文章存档
  • 2016年05月(1)
  • 2015年03月(1)
  • 2014年08月(2)
  • 2014年07月(1)
  • 2013年05月(2)
  • 展开

【1024程序员节】参加活动领暖心礼品     【观点】有了深度学习,你还学传统机器学习算法么?     【知识库】深度学习知识图谱上线啦
 

[置顶] 并查集详解 (转)

标签: join算法电话编程优化
 49737人阅读 评论(79) 收藏 举报
 分类:

这个文章是几年前水acm的时候转的, 当时也不知道作者是谁, 要是有人知道的话说一下吧


并查集是我暑假从高手那里学到的一招,觉得真是太精妙的设计了。以前我无法解决的一类问题竟然可以用如此简单高效的方法搞定。不分享出来真是对不起party了。(party:我靠,关我嘛事啊?我跟你很熟么?)

来看一个实例,杭电1232畅通工程

首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题。比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块。像畅通工程这题,问还需要修几条路,实质就是求有几个连通分支。如果是1个连通分支,说明整幅图上的点都连起来了,不用再修路了;如果是2个连通分支,则只要再修1条路,从两个分支中各选一个点,把它们连起来,那么所有的点都是连起来的了;如果是3个连通分支,则只要再修两条路……

以下面这组数据输入数据来说明

4 2 1 3 4 3

第一行告诉你,一共有4个点,2条路。下面两行告诉你,1、3之间有条路,4、3之间有条路。那么整幅图就被分成了1-3-4和2两部分。只要再加一条路,把2和其他任意一个点连起来,畅通工程就实现了,那么这个这组数据的输出结果就是1。好了,现在编程实现这个功能吧,城镇有几百个,路有不知道多少条,而且可能有回路。 这可如何是好?

我以前也不会呀,自从用了并查集之后,嗨,效果还真好!我们全家都用它!

并查集由一个整数型的数组和两个函数构成。数组pre[]记录了每个点的前导点是什么,函数find是查找,join是合并。

int pre[1000 ];

int find(int x)                                                                                                         //查找根节点

    int r=x;

    while ( pre[r ] != r )                                                                                              //返回根节点 r

          r=pre[r ];

 

    int i=x , j ;

    while( i != r )                                                                                                        //路径压缩

    {

         j = pre[ i ]; // 在改变上级之前用临时变量  j 记录下他的值 

         pre[ i ]= r ; //把上级改为根节点

         i=j;

    }

    return r ;

}

 

 

void join(int x,int y)                                                                                                    //判断x y是否连通,

                                                                                             //如果已经连通,就不用管了 //如果不连通,就把它们所在的连通分支合并起,

{

    int fx=find(x),fy=find(y);

    if(fx!=fy)

        pre[fx ]=fy;

}

 

为了解释并查集的原理,我将举一个更有爱的例子。 话说江湖上散落着各式各样的大侠,有上千个之多。他们没有什么正当职业,整天背着剑在外面走来走去,碰到和自己不是一路人的,就免不了要打一架。但大侠们有一个优点就是讲义气,绝对不打自己的朋友。而且他们信奉“朋友的朋友就是我的朋友”,只要是能通过朋友关系串联起来的,不管拐了多少个弯,都认为是自己人。这样一来,江湖上就形成了一个一个的群落,通过两两之间的朋友关系串联起来。而不在同一个群落的人,无论如何都无法通过朋友关系连起来,于是就可以放心往死了打。但是两个原本互不相识的人,如何判断是否属于一个朋友圈呢?

我们可以在每个朋友圈内推举出一个比较有名望的人,作为该圈子的代表人物,这样,每个圈子就可以这样命名“齐达内朋友之队”“罗纳尔多朋友之队”……两人只要互相对一下自己的队长是不是同一个人,就可以确定敌友关系了。

但是还有问题啊,大侠们只知道自己直接的朋友是谁,很多人压根就不认识队长,要判断自己的队长是谁,只能漫无目的的通过朋友的朋友关系问下去:“你是不是队长?你是不是队长?”这样一来,队长面子上挂不住了,而且效率太低,还有可能陷入无限循环中。于是队长下令,重新组队。队内所有人实行分等级制度,形成树状结构,我队长就是根节点,下面分别是二级队员、三级队员。每个人只要记住自己的上级是谁就行了。遇到判断敌友的时候,只要一层层向上问,直到最高层,就可以在短时间内确定队长是谁了。由于我们关心的只是两个人之间是否连通,至于他们是如何连通的,以及每个圈子内部的结构是怎样的,甚至队长是谁,并不重要。所以我们可以放任队长随意重新组队,只要不搞错敌友关系就好了。于是,门派产生了。

http://i3.6.cn/cvbnm/6f/ec/f4/1e9cfcd3def64d26ed1a49d72c1f6db9.jpg


下面我们来看并查集的实现。 int pre[1000]; 这个数组,记录了每个大侠的上级是谁。大侠们从1或者0开始编号(依据题意而定),pre[15]=3就表示15号大侠的上级是3号大侠。如果一个人的上级就是他自己,那说明他就是掌门人了,查找到此为止。也有孤家寡人自成一派的,比如欧阳锋,那么他的上级就是他自己。每个人都只认自己的上级。比如胡青牛同学只知道自己的上级是杨左使。张无忌是谁?不认识!要想知道自己的掌门是谁,只能一级级查上去。 find这个函数就是找掌门用的,意义再清楚不过了(路径压缩算法先不论,后面再说)。

int find(int x)                                                                  //查找我(x)的掌门

{

    int r=x;                                                                       //委托 r 去找掌门

    while (pre[r ]!=r)                                                        //如果r的上级不是r自己(也就是说找到的大侠他不是掌门 = =)

    r=pre[r ] ;                                                                   // r 就接着找他的上级,直到找到掌门为止。

    return  r ;                                                                   //掌门驾到~~~

}

再来看看join函数,就是在两个点之间连一条线,这样一来,原先它们所在的两个板块的所有点就都可以互通了。这在图上很好办,画条线就行了。但我们现在是用并查集来描述武林中的状况的,一共只有一个pre[]数组,该如何实现呢? 还是举江湖的例子,假设现在武林中的形势如图所示。虚竹小和尚与周芷若MM是我非常喜欢的两个人物,他们的终极boss分别是玄慈方丈和灭绝师太,那明显就是两个阵营了。我不希望他们互相打架,就对他俩说:“你们两位拉拉勾,做好朋友吧。”他们看在我的面子上,同意了。这一同意可非同小可,整个少林和峨眉派的人就不能打架了。这么重大的变化,可如何实现呀,要改动多少地方?其实非常简单,我对玄慈方丈说:“大师,麻烦你把你的上级改为灭绝师太吧。这样一来,两派原先的所有人员的终极boss都是师太,那还打个球啊!反正我们关心的只是连通性,门派内部的结构不要紧的。”玄慈一听肯定火大了:“我靠,凭什么是我变成她手下呀,怎么不反过来?我抗议!”抗议无效,上天安排的,最大。反正谁加入谁效果是一样的,我就随手指定了一个。这段函数的意思很明白了吧?

void join(int x,int y)                                                                   //我想让虚竹和周芷若做朋友

{

    int fx=find(x),fy=find(y);                                                       //虚竹的老大是玄慈,芷若MM的老大是灭绝

    if(fx!=fy)                                                                               //玄慈和灭绝显然不是同一个人

    pre[fx ]=fy;                                                                           //方丈只好委委屈屈地当了师太的手下啦

}

再来看看路径压缩算法。建立门派的过程是用join函数两个人两个人地连接起来的,谁当谁的手下完全随机。最后的树状结构会变成什么胎唇样,我也完全无法预计,一字长蛇阵也有可能。这样查找的效率就会比较低下。最理想的情况就是所有人的直接上级都是掌门,一共就两级结构,只要找一次就找到掌门了。哪怕不能完全做到,也最好尽量接近。这样就产生了路径压缩算法。 设想这样一个场景:两个互不相识的大侠碰面了,想知道能不能揍。 于是赶紧打电话问自己的上级:“你是不是掌门?” 上级说:“我不是呀,我的上级是谁谁谁,你问问他看看。” 一路问下去,原来两人的最终boss都是东厂曹公公。 “哎呀呀,原来是记己人,西礼西礼,在下三营六组白面葫芦娃!” “幸会幸会,在下九营十八组仙子狗尾巴花!” 两人高高兴兴地手拉手喝酒去了。 “等等等等,两位同学请留步,还有事情没完成呢!”我叫住他俩。 “哦,对了,还要做路径压缩。”两人醒悟。 白面葫芦娃打电话给他的上级六组长:“组长啊,我查过了,其习偶们的掌门是曹公公。不如偶们一起及接拜在曹公公手下吧,省得级别太低,以后查找掌门麻环。” “唔,有道理。” 白面葫芦娃接着打电话给刚才拜访过的三营长……仙子狗尾巴花也做了同样的事情。 这样,查询中所有涉及到的人物都聚集在曹公公的直接领导下。每次查询都做了优化处理,所以整个门派树的层数都会维持在比较低的水平上。路径压缩的代码,看得懂很好,看不懂也没关系,直接抄上用就行了。总之它所实现的功能就是这么个意思。

http://i3.6.cn/cvbnm/60/98/92/745b3eac68181e4ee1fa8d1b8bca38bc.jpg


 

 

hdu1232

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include<iostream>  
  2. using namespace std;  
  3.   
  4. int  pre[1050];  
  5. bool t[1050];               //t 用于标记独立块的根结点  
  6.   
  7. int Find(int x)  
  8. {  
  9.     int r=x;  
  10.     while(r!=pre[r])  
  11.         r=pre[r];  
  12.       
  13.     int i=x,j;  
  14.     while(pre[i]!=r)  
  15.     {  
  16.         j=pre[i];  
  17.         pre[i]=r;  
  18.         i=j;  
  19.     }  
  20.     return r;  
  21. }  
  22.   
  23. void mix(int x,int y)  
  24. {  
  25.     int fx=Find(x),fy=Find(y);  
  26.     if(fx!=fy)  
  27.     {  
  28.         pre[fy]=fx;  
  29.     }  
  30. }   
  31.   
  32. int main()  
  33. {  
  34.     int N,M,a,b,i,j,ans;  
  35.     while(scanf("%d%d",&N,&M)&&N)  
  36.     {  
  37.         for(i=1;i<=N;i++)          //初始化   
  38.             pre[i]=i;  
  39.           
  40.         for(i=1;i<=M;i++)          //吸收并整理数据   
  41.         {  
  42.             scanf("%d%d",&a,&b);  
  43.             mix(a,b);  
  44.         }  
  45.           
  46.           
  47.         memset(t,0,sizeof(t));  
  48.         for(i=1;i<=N;i++)          //标记根结点  
  49.         {  
  50.             t[Find(i)]=1;  
  51.         }  
  52.         for(ans=0,i=1;i<=N;i++)  
  53.             if(t[i])  
  54.                 ans++;  
  55.                   
  56.         printf("%d\n",ans-1);  
  57.           
  58.     }  
  59.     return 0;  
  60. }//dellaserss  


以下为原文附的代码:

 

回到开头提出的问题,我的代码如下:

#include int pre[1000 ];

int find(int x)

{

    int r=x;

   while (pre[r ]!=r)

   r=pre[r ];

   int i=x; int j;

   while(i!=r)

   {

       j=pre[i ];

       pre[i ]=r;

       i=j;

   }

   return r;

}

int main()

{

   int n,m,p1,p2,i,total,f1,f2;

   while(scanf("%d",&n) && n)         //读入n,如果n为0,结束

   {                                                    //刚开始的时候,有n个城镇,一条路都没有 //那么要修n-1条路才能把它们连起来

       total=n-1;

       //每个点互相独立,自成一个集合,从1编号到n //所以每个点的上级都是自己

       for(i=1;i<=n;i++) { pre[i ]=i; }                //共有m条路

       scanf("%d",&m); while(m--)

       { //下面这段代码,其实就是join函数,只是稍作改动以适应题目要求

           //每读入一条路,看它的端点p1,p2是否已经在一个连通分支里了

           scanf("%d %d",&p1,&p2);

           f1=find(p1);

           f2=find(p2);

               //如果是不连通的,那么把这两个分支连起来

               //分支的总数就减少了1,还需建的路也就减了1

           if(f1!=f2)

            {

               pre[f2 ]=f1;

               total--;

           }

           //如果两点已经连通了,那么这条路只是在图上增加了一个环 //对连通性没有任何影响,无视掉

       }

//最后输出还要修的路条数

       printf("%d\n",total);

   }

   return 0;

}

 

96
0
 
 

我的同类文章

  • hdu3555 数位dp入门题2013-05-09
  • poj1741Tree 树的分治 树形dp 男人八题....2013-04-26
  • hdu2196Computer 经典树形dp 在树上求最长距离2013-04-18
  • POJ1947 树形dp 重做2013-04-16
  • poj1155TELE - 树形dp2013-04-15
  • hdu3535 01&分组背包2013-04-11
  • poj3107 树的重心 非stl实现2013-05-06
  • poj1655Balancing Act 树的重心,树形dp2013-04-23
  • hdu1520 Anniversary party 树形dp2013-04-18
  • hdu1011Starship Troopers 树形DP2013-04-15
  • hdu1561树形DP入门2013-04-14
更多文章

参考知识库

img

算法与数据结构知识库

猜你在找
数据结构和算法
数据结构基础系列(1):数据结构和算法
以性别预测为例,谈谈数据挖掘中常见的分类算法
模板匹配的字符识别(OCR)算法原理
Python算法实战视频课程--二叉树
并查集详解 转
并查集详解转
并查集详解转
并查集详解 转
并查集详解 转
查看评论
76楼 yongf2014 2016-09-15 21:58发表 [回复]
这个可以有。。。
75楼 cqweimingdan 2016-09-14 08:59发表 [回复]
赞!!
74楼 AnXT 2016-09-05 18:55发表 [回复]
讲的太棒了,赞一个!
73楼 陈小fat 2016-08-27 00:05发表 [回复]
感觉写得好通俗易懂~赞一个,可以转载吗?~
72楼 smileFFFF 2016-08-17 22:04发表 [回复]
一遍就懂~ 学习如此轻松
71楼 yyoc97 2016-08-11 17:30发表 [回复]
受教了!!
70楼 tingyun_say 2016-07-25 11:26发表 [回复]
mark了,听了个故事看懂了一个算法
69楼 项三六 2016-07-25 11:25发表 [回复]
怒评一波,刚刚老师讲得我昏昏欲睡
68楼 Onwaier 2016-07-23 21:29发表 [回复]
真心的不错,从未觉得学习可以轻松。。
67楼 qq_35650561 2016-07-19 20:57发表 [回复]
清晰明了,讲的很详细
66楼 yakoazz 2016-07-11 22:06发表 [回复]
太有趣啦,讲的真好,处女评论,哈哈
65楼 Brave-girl 2016-06-24 15:17发表 [回复]
第一次评论,简直不能再赞!!!
64楼 klc1 2016-06-09 21:17发表 [回复]
楼主这么可爱一定是个妹子!
63楼 澜水 2016-05-17 14:15发表 [回复]
竟然听懂了T^T,赞!!

但是那个路径压缩的链接进不去了,让我在你的代码里再找一圈
62楼 lethalboy 2016-05-10 09:46发表 [回复]
膜拜楼主,讲的好极了
61楼 _涧边幽草 2016-05-03 22:01发表 [回复]
谢谢
60楼 Puyar_ 2016-05-01 18:39发表 [回复]
楼主自己贴的那个代码过不了的。。。。
59楼 zha0zha0zha 2016-04-27 21:51发表 [回复]
这个必须赞
58楼 Lee_Handsome 2016-04-19 19:44发表 [回复]
真心6,讲得好
57楼 chen_hongdong 2016-04-16 21:52发表 [回复]
讲得真好
56楼 imGala 2016-03-23 16:26发表 [回复]
讲得太好了,头次见到这么有意思的算法博客,赞个
55楼 tudou_0 2016-03-18 12:05发表 [回复]
赞一个
54楼 oney_hu 2016-03-08 09:39发表 [回复]
Mark
53楼 sxy_799 2016-02-29 22:08发表 [回复]
太有才了
52楼 qq_28859199 2016-02-20 10:07发表 [回复]
讲得好,妈妈再也不用担心我用打火机了
51楼 lemonoil 2016-01-26 16:32发表 [回复]
第一次评论,真心可以
50楼 qq_33688788 2016-01-09 19:24发表 [回复]
真棒!我自己看课件看了老半天看得快睡着了,看完这篇文章一下子就明白了!
49楼 少年呀 2015-12-04 17:48发表 [回复]
虽然是转的,但还是要给你赞
48楼 EatAppleS 2015-11-27 15:22发表 [回复]
感觉和two-path连通域搜索,挺像的
47楼 bwju 2015-11-26 12:18发表 [回复]
我的第一次评论,原创作者真是太厉害了
46楼 ljlstart 2015-10-08 21:16发表 [回复]
赞!!!!!!!!!!1
45楼 qq8871647 2015-09-27 15:54发表 [回复]
十分感谢
44楼 wahaha111111111 2015-09-20 16:01发表 [回复]
天呐,真的只要一遍!!!!!!1
43楼 CourageK 2015-09-17 19:45发表 [回复]
之前一直听我身边的同学提起并查集,他们讲得口若悬河,但是我一直不太明白。今天趁着在复习数据结构的机会,学习了这篇博客,觉得很浅显易懂,谢谢你~
42楼 youhebuke52011 2015-09-14 21:57发表 [回复]
6666666666
41楼 vcmfsmsrm 2015-09-10 16:31发表 [回复]
好文章~~有意思
40楼 NemoEvertt 2015-09-08 18:33发表 [回复]
mark
39楼 huangkailnn 2015-09-01 15:06发表 [回复]
非常好的文章
38楼 baidu_30779555 2015-08-22 18:23发表 [回复]
感谢楼主 并查集 一下就懂了
37楼 fsafdsafsa 2015-08-19 15:24发表 [回复]
真不错!
36楼 sunshine_YG 2015-08-10 22:31发表 [回复]
nice
35楼 justry24 2015-08-10 17:20发表 [回复]
听君一席话,胜看俩小时书!
34楼 yin19930412 2015-08-03 15:43发表 [回复]
楼主我觉得我快要爱上你了,讲的不能再赞
33楼 qq_30233451 2015-07-30 14:52发表 [回复]
妈的,写的太好了,一看即懂,妈妈再也不用担心我的学习
32楼 coderhzx 2015-07-30 13:26发表 [回复]
欢乐的讲解o(∩_∩)o ,收藏了
31楼 大个儿柚子 2015-07-29 09:34发表 [回复]
写的太好了。感谢感谢
30楼 liliangwei_sau 2015-07-26 15:38发表 [回复]
写得太好了,十分感谢。
29楼 gxfcome 2015-07-21 20:30发表 [回复]
写得很有意思
28楼 ZeroMem_0 2015-07-20 18:49发表 [回复]
有一个问题没想明白。
路径应该是双向的比如数据里面有一行是(3,7)就是说pre[3] = 7, pre[7] = 3.但是博主这个好像没体现出来
Re: ZeroMem_0 2015-07-20 19:02发表 [回复]
回复ZeroMem_0:刚才自己画图试了一下,即使是双向的,检查连同性的时候是不会出问题的。看来是一开是没弄清出并查集的应用背景。
27楼 zju兔子哥哥 2015-07-20 15:34发表 [回复]
66666
26楼 qq_21042919 2015-07-14 19:54发表 [回复]
学习了2333
25楼 chengchaoli 2015-06-28 14:58发表 [回复]
玄慈做了灭绝的手下。。写的真好
24楼 sinat_29166571 2015-06-19 20:22发表 [回复]
写的已经不能再棒
23楼 技术宅--火狼 2015-06-17 18:40发表 [回复]
楼主,太可爱了,举的例子萌萌哒啊!一看就懂啊!!
22楼 ningai007 2015-06-15 10:23发表 [回复]
讲解的很明白,真心喜欢~~~
21楼 holly_green 2015-06-06 15:45发表 [回复]
这样要求连通子图的边的输入是以一种顺序的遍历的输入,对于一些乱序输入的题目无法压缩
20楼 sxxymzy 2015-05-28 20:17发表 [回复]
从来没评论过,但是这篇写得太棒了,点赞!!
19楼 dangeroushai 2015-05-26 11:22发表 [回复]
受教,谢过!
18楼 chenchukun 2015-05-21 22:16发表 [回复]
写得真好,之前一直不是很明白,现在懂了,谢谢。
17楼 yang1018679 2015-05-13 11:07发表 [回复]
简单易懂,还有趣。
16楼 牛炖 2015-05-12 17:46发表 [回复]
看乐了,瞬间明白
15楼 _天道酬勤_不忘初心 2015-04-24 20:43发表 [回复]
HDU 1232不用标记根节点,直接for(i=1;i<=n;i++)
{
if(pre[i]==i)
ans++;
}即可
14楼 杨汉祥 2015-04-22 20:28发表 [回复]
写的真的很nice啊!
13楼 mzzzzq 2015-04-15 15:10发表 [回复]
懂了,多谢
12楼 mzzzzq 2015-04-15 15:09发表 [回复]
要是算法老师都这样形象的讲课,那就好了
11楼 sdauwcy 2015-04-13 22:26发表 [回复]
简单易懂!多谢!
10楼 Ftworld21 2015-04-13 17:40发表 [回复]
以前一直没搞懂这个并查集是什么意思 也看不懂 看了你写的文章后 豁然开朗 多谢大侠分享
9楼 tt2767 2015-03-29 11:40发表 [回复]
路径压缩里面为什么要保留上级的信息,直接覆盖不就好了么?
Re: tt2767 2015-03-29 11:40发表 [回复]
回复tt2767:。。。。看懂了
Re: _天道酬勤_不忘初心 2015-04-24 18:48发表 [回复]
回复tt2767:四弟告诉三弟咱的老大是谁,然后三弟告诉二弟咱的老大是谁,二弟的老大就是老大就不用告诉了
Re: _天道酬勤_不忘初心 2015-04-24 18:47发表 [回复]
回复tt2767:四弟告诉三弟咱的老大是谁,三弟再告诉二弟咱的老大是谁,二弟的老大就是老大就不用告诉了
8楼 茶叶团子 2015-03-27 21:05发表 [回复]
明明是讲算法的,我看乐了
7楼 ProjectDD 2015-03-05 09:48发表 [回复]
写得真好 点赞
6楼 MSJ_CS 2015-02-05 15:52发表 [回复]
好棒,看完居然可以自己写了。。点赞!
5楼 Clarehehe 2015-02-02 10:37发表 [回复]
清晰易懂,受教了
4楼 -releaner- 2015-01-12 17:38发表 [回复]
简单易懂,一看就会~\(≧▽≦)/~
3楼 haoflynet 2013-12-20 18:29发表 [回复]
写得很好,看一遍就懂
2楼 wu0402204 2013-10-24 16:06发表 [回复]
通俗易懂,写的真不错!mack一下!
1楼 NYIST_creat2012 2013-10-23 21:42发表 [回复]
并查集是否有快速查找的用法,比如呢?
发表评论
  • 用 户 名:
  • github_35957188
  • 评论内容:
  • 插入代码
      
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
核心技术类目
全部主题 Hadoop AWS 移动游戏 Java Android iOS Swift 智能硬件 Docker OpenStack VPN Spark ERP IE10Eclipse CRM JavaScript 数据库 Ubuntu NFC WAP jQuery BI HTML5 Spring Apache .NET API HTML SDK IISFedora XML LBS Unity Splashtop UML components Windows Mobile Rails QEMU KDE Cassandra CloudStack FTCcoremail OPhone CouchBase 云计算 iOS6 Rackspace Web App SpringSide Maemo Compuware 大数据 aptech PerlTornado Ruby Hibernate ThinkPHP HBase Pure Solr Angular Cloud Foundry Redis Scala Django Bootstrap
    个人资料
     
    laserss
     
    • 访问:168502次
    • 积分:2666
    • 等级: 
    • 排名:第10113名
    • 原创:125篇
    • 转载:10篇
    • 译文:0篇
    • 评论:96条
    文章分类
  • 最短路(11)
  • 动态规划(29)
  • 母函数(8)
  • 简单题(8)
  • - -(6)
  • zoj(2)
  • pku(25)
  • hdu(75)
  • acm(112)
  • 计算几何(5)
  • 数学(16)
  • 贪心(2)
  • 字典树(4)
  • BST(2)
  • dfs(5)
  • 二分图(2)
  • bfs(6)
  • 模板(15)
  • 博弈(1)
  • hash(1)
  • 字符串(3)
  • 图论~(5)
  • wind(0)
  • windows sdk(3)
  • HLSL(1)
    阅读排行
  • 并查集详解 (转)(49713)
  • hdu2073-无限的路(4266)
  • 程序员装逼指南(4129)
  • hdu,poj 分类(2853)
  • hdu1269 Tarjan强连通分量 模板(2160)
  • hdu1561树形DP入门(1988)
  • hdu2824筛选法欧拉函数+求和(1973)
  • hdu2586 LCA模板(1937)
  • hdu 2059 龟兔赛跑 动态规划(1936)
  • ACM 推荐blog汇总及OJ(1875)
    文章存档
  • 2016年05月(1)
  • 2015年03月(1)
  • 2014年08月(2)
  • 2014年07月(1)
  • 2013年05月(2)
    展开

0 0