并查集入门

我是看着《啊哈!算法》这本书完成并查集的入门,本想举出另外的栗子,奈何。。。书上的栗子已经很贴切了

首先引入一个问题:已知有10个土匪,警方需要需要一点点顺藤摸瓜最后挖出他们各自背后的团伙一锅端,经过一段时间的侦查警方的得到了9条确切线索,分别能说明那两个土匪的归顺关系。那么请问此次行动总共要打掉几个团伙?

输入数据如下:

按照第一行输入人数n,线索数m,接下来的m行输入线索,每行线索如1 2代表1号和2号土匪是一伙的。现提供一组数据以供后续讲解和程序测试:

<span style="font-size:18px;">10 9
1 2
3 4
5 2
4 6
2 6
8 7
9 7
1 6
2 4</span>

这组数据应该输出几呢?让我们一点点分析。

1:首先申请一个一维数组f,用下标1~10来标记这10个土匪,每个元素对应的数值来代表每个土匪的老大是谁。

2:进行初始化,一开始我们先假设各个土匪“各自为政”,即 f[1]=1, f[2]=2 ......f[i] = i ;都以自身为BOSS

3:开始处理线索,首先第一条线索1 2,可以发现1号和2号是一伙的,那么到底是让1号归顺2号还是2号归顺1号呢?这里我们先按照“靠左”法则,让2号归顺一号,即个f[2] = 1 ; 此时f数组变为

1 1 3 4 5 6 7 8 9 10

然后开始处理第二条线索,3 4,同理根据“靠左法则”  f[4] = 3 ; 此时f数组变为:

1 1 3 3 5 6 7 8 9 10

继续第三条线索 5 2,已知f[5] = 5,说明5号的BOSS是自己,对于2号f[2] = 1 ;说明2号的BOSS是1号,此时仍然按照“靠左”法则的话,让2号归顺5号即f[2] = 5 ;那么1号强盗就不干了。为什么枪我的人(f[2] =1)?此时出现矛盾,怎么办呢??? 此时引入另一法则----->擒贼先擒王!!直接找2号的BOSS谈,让2号的BOSS 1号归顺5号即f[1]=5,矛盾解决!!第三条线索处理完毕,此时f数组为:

5 5 3 3 5 6 7 8 9 10

到这里有了靠左法则和擒贼先擒王法则以后的6条线索都能被顺利处理,这里不在赘述处理过程,直接给出每次处理以后的f数组

5 5 3 3 5 3 7 8 9 10

5 5 5 3 5 5 78 9 10

5 5 5 3 5 5 8 8 9 10

5 5 5 3 5 5 9 9 9 10

最终团伙关系清晰呈现在眼前:

2 1 3 4 6的BOSS是5号

10号自己当自己的BOSS

8 7的BOSS是9号

所以一共有三个团伙! 问题圆满解决,

ps:详细过程可以参照《啊哈!算法》 200页,下面给出解题代码:

<span style="font-size:18px;">#include <cstdio>
#include <iostream>
using namespace std ;

int f[1000]  ;   //定义各个元素
int n,m ;            //总人数n和已知的关系的数目
int x,y ;           //一组关系  如 1 2代表1号2号为一伙 
void init()    //进行初始化
{
    for(int i = 1 ;i<=n ;i++)
    {
        f[i] = i ;
    }
}

int getf(int v)    //不停的去找自己的宿主
{
    if(f[v] == v)
        return v ;
    else
    {
        f[v] = getf(f[v]) ;
        return f[v] ;
    }
}

void merge(int v,int u)    //归并函数
{
    int t1,t2 ;
    t1 = getf(v) ;
    t2 = getf(u) ;
    if(t1 != t2)      //按照左边优先的原则,让t2归顺t1
    {
        f[t2] = t1 ;
    }
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init() ;
        for(int i = 0 ;i<m ;i++)
        {
            scanf("%d%d",&x,&y) ;
            merge(x,y) ;
        }
        int sum = 0 ;      //统计团伙数目sum
        for(int i = 1 ;i<=n ;i++)
        {
            if(f[i] == i)
                sum++ ;
        }
        printf("总共有%d个团伙\n",sum) ;
    }
 return 0 ;
}

</span>
时间: 2024-08-22 06:07:04

并查集入门的相关文章

hdu1272并查集入门

小希的迷宫 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 41540    Accepted Submission(s): 12811 Problem Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是

hdu 1213 并查集入门

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1213 How Many Tables Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 12538    Accepted Submission(s): 6145 Problem Description Today is Ignatius' b

并查集入门(转)

并查集入门 并查集学习: l 并查集:(union-find sets) 一种简单的用途广泛的集合. 并查集是若干个不相交集合,能够实现较快的合并和判断元素所在集合的操作,应用很多,如其求无向图的连通分量个数等.最完美的应用当属:实现Kruskar算法求最小生成树. l 并查集的精髓(即它的三种操作,结合实现代码模板进行理解): 1.Make_Set(x) 把每一个元素初始化为一个集合 初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变). 2.Find_S

并查集(入门)

首先先看一道很简单的并查集的题目:https://vjudge.net/contest/297398#problem/A 这道题就是让你判断两两城镇之间是否联通 如果不联通就要修建一条道路 就我的理解来说,如果单独使用并查集就是为了合并有相同根结点(或者理解成有相同的性质)的这样的数据 这里我们引入一个我在网上看到的一个关于并查集的一个很有意思的故事: 并查集由一个整数型的数组和两个函数构成.数组pre[]记录了每个点的前导点是什么 函数find是查找 函数join是合并. 话说江湖上散落着各式

POJ1611 The Suspects: 并查集入门

#include<iostream> using namespace std; #define Size 30000 int Pre[Size+1], Sum[Size+1];// Sum[i] 表示 第i组 的人数 int Get_Pre( int a ) { if( Pre[a]!=a ) a = Get_Pre( Pre[a] );// 路径压缩 return a; } void Union( int a, int b ) { int P1 = Get_Pre(a); int P2 =

并查集题目从入门到入土

2017-09-01 并查集一个神奇的算法 今天我们的s同学想学习一下并查集,就去找了几个水题刷一下... 入门题_1:P2839 畅通工程 畅通工程 就是求联通块的数量,-1就是答案. #include<iostream> #include<cstdio> #include<cstdlib> using namespace std; int read(){ int f=1,an=0; char ch=getchar(); while(!('0'<=ch&

poj 2524:Ubiquitous Religions(并查集,入门题)

Ubiquitous Religions Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 23997   Accepted: 11807 Description There are so many different religions in the world today that it is difficult to keep track of them all. You are interested in findi

(DS 《算法竞赛入门经典》)LA 3644 X-Plosives(并查集)

解题思路: 并查集 A secret service developed a new kind of explosive that attain its volatile property only when a specificassociation of products occurs. Each product is a mix of two different simple compounds, to which wecall a binding pair. If N > 2, then

并查集基础(入门)

最早接触并查集的时候是在做一道最小生成树问题上,当时还不会并查集,题解说用克鲁斯卡尔算法,用并查集来维护,就能够完成最小生成树. 并查集是什么呢?其实,并查集就是一个集合,它有两种操作,一个是合并(merge),一个是查找(getf). 合并就是说把具有相同祖先的集合合并成 为一个集合,查找就是说,查找某些具有相同祖先的集合.当然这个祖先只是我这样叫的(他其实并不是名义上的祖先),很多时候我们会维护很多 这样的信息,比如说,在求最小生成树的算法中,我们维护的是检查两个顶点是否属于同一个集合,也就