并查集(擒贼先擒王)

原创 2016年08月30日 19:56:39

并查集是若干个集合,可以判断两个对象是否在一个集合中,从而判断它们需不需要进行一个操作。

每个集合都是一棵树(注意不一定是二叉树),这里说一下二叉树和其他树的一点区别,二叉树编号是按位置来的(一棵二叉树一开始是怎样就一直是怎样,变的只是每个节点的值,编号永远不会改,父亲节点也永远不会改),而其他树的编号是按新建节点的顺序来的,越前添加的新节点编号越小(这个编号可以移动,比如某个节点的父亲节点可以变成它的父亲节点的父亲节点,这也就是并查集的一种操作)。

比如看一道例题

有若干个强盗 有若干个线索,每个线索中的两个强盗为同伙(倘若A与B是同伙,B与C是同伙,那么A与C也是同伙),判断有多少个独立的犯罪团伙。

样例数据:

10 9//10个强盗 9条线索

1 2

3 4

5 2

4 6

2 6

8 7

9 7

1 6

2 4

显然,在线索输入之前,每个强盗都是一个犯罪团伙,每次读入一个线索,就将为同伙的两个强盗的团伙合并为一个团伙。

为了方便,每个团伙都会有一个“老大”,至于有什么用,待会就知道了,显然一开始每个强盗都是自己团队的老大,合并的时候需要找到两个团伙的老大,然后将其中一个老大的上司更新为另一个老大。

fa[i]代表第i个强盗的直接上司的编号,注意是直接上司,它的直接上司有可能还有上司,直到它的上司的上司的上司……(若干个上司)的上司仍是自己的时候,这个强盗才是这个团伙真正的老大,显然,最后只需要判断,有多少个强盗的老大就是他自己,就是最终答案。

上代码

#include<cstdio>
using namespace std;
int fa[500];
void together(int x,int y){
	fa[x]=y;//y变成了x团伙的老大的老大 
	return ;
}
//有些代码还查询x与y的树的深度 再判断是x合并到y还是y合并到x更优化 而这里有将节点直接接到根节点的优化 所以循环不会太多 理论上应该不会超过3次 
int dfs(int h){
	if(fa[h]==h)return h;
	return fa[h]=dfs(fa[h]);
}
/*
这里函数很简单,但是有个很重要的优化。
如果一个强盗的上司是他自己说明他就是老大 那么直接返回他自己(这个很简单)
而当一个强盗的上司不是他自己时,就将他的上司赋值为他的上司的老大,比如说一个强盗的上司的上司的上司......(200个上司后)的上司是老大 那么如果再次查询这个点又要循环200次 而如果直接赋值成老大 那么他只需要向上搜一次 即使将这个团伙合并到别的团伙(即他的老大的上司被赋值了)也只需要搜两次 
*/
int main(){
	int i,j,k,m,n,x,y,ans=0;
	scanf("%d %d",&n,&m);
	for(i=1;i<=n;i++)fa[i]=i;//当读入线索之前,每个团伙的强盗都只有一个,每个强盗都是自己团伙的老大 
	for(i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		together(dfs(x),dfs(y));//dfs[h]代表第h个强盗的老大 
	}
	for(i=1;i<=n;i++){
		if(fa[i]==i)ans++;
	}
	printf("%d",ans);
	return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

擒贼先擒王--并查集

快过年了,犯罪分子也开始为年终奖奋斗了。晓哼的家乡出现了多次抢劫事件。由于强盗人数过于庞大,作案频繁,警方想查清楚到底有几个犯罪团伙实在太不容易了,不过警察叔叔还是搜集到了一些线索,需要咱们帮忙分析一...
  • qq_16997551
  • qq_16997551
  • 2016年03月08日 15:57
  • 515

并查集—解密犯罪团伙

警察想查清楚有几个犯罪团伙,搜集到了一些线索: 现在有10个强盗; 1号强盗与2号强盗是同伙; 3号强盗与4号强盗是同伙; 5号强盗与2号强盗是同伙; 4号强盗与6号强盗是同伙; 2号强盗...
  • wtyvhreal
  • wtyvhreal
  • 2015年02月04日 21:39
  • 2535

擒贼先擒王-并查集

并查集通过一个一维数组来实现,其本质是维护一个森林。刚开始时候,森林的每个点都是孤立的,也可以理解为每个点就是一颗只有一个结点的树,之后通过一些条件,逐渐将这些树合并为一颗大树。 其实合并的过程就是认...
  • wangdd_199326
  • wangdd_199326
  • 2017年04月22日 18:57
  • 192

7.2擒贼先擒王——并查集

#include using namespace std; int f[1000]={0},n,m,k,sum=0; //初始化函数,数组里面存的是自己数组下标的编号 void init(){ i...
  • shaguabufadai
  • shaguabufadai
  • 2017年03月14日 22:09
  • 140

擒贼先擒王

#include using namespace std; int h[1000]; void init() { int i; for(i=1;i
  • superna666
  • superna666
  • 2016年11月03日 18:48
  • 87

[Aha]擒贼先擒王

题目:详见啊哈算法P200页。就是并查集的裸题。 分析:裸题呀,理解并背下代码。 代码:#include #include #include using namespace std ;int f[...
  • qq_24294439
  • qq_24294439
  • 2017年03月07日 23:45
  • 75

使用STL实现并查集

我以最入门的并查集水题——宗教信仰为例,来演示使用STL里的multimap(多重映照容器)模拟并查集数据结构(并查集应该也可以用其他STL实现,这里我仅以multimap为例)。 Multimap...
  • lhrsdl
  • lhrsdl
  • 2014年07月25日 15:43
  • 1677

并查集 -- 学习详解

作者:Yx.Ac 出处:勇幸|Thinking (http://www.ahathinking.com)         昨天和今天学习了并查集和trie树,并练习了三道入门题目,理解...
  • JDPlus
  • JDPlus
  • 2014年02月19日 16:50
  • 3859

图—并查集(解决朋友圈问题)

图也是一种 非线性结构,是由多个顶点组成的关系集合组成的一种数据结构。图可以分为两种,无向图和有向图。★图的定义:650) this.width=650;" width="525" height="2...
  • ttyue_123
  • ttyue_123
  • 2016年08月09日 21:44
  • 617

【并查集专题】【HDU】

How Many Tables Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...
  • zy691357966
  • zy691357966
  • 2014年11月29日 18:34
  • 2259
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:并查集(擒贼先擒王)
举报原因:
原因补充:

(最多只允许输入30个字)