博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
并查集入门(普通并查集+带删除并查集+关系并查集)
阅读量:3898 次
发布时间:2019-05-23

本文共 2352 字,大约阅读时间需要 7 分钟。

什么是并查集?

【普通并查集】

【How Many Tables】

Problem Description

Lh Boy无聊的时候很喜欢数蚂蚁,而且,还给每一只小蚂蚁编号,通过他长期的观察和记录,发现编号为i的蚂蚁会和编号为j的蚂蚁在一起。

现在问题来了,他现在只有他的那本记录本,然而,他想要知道,他所观察的蚂蚁中,有多少堆蚁群。没有记录的编号则作为独自一个一堆。

Input

第一行输入一个整数T,表示有T(1<=T<=25)组测试案例。每一组测试案例,先输入两个整数N和M,分别表示蚂蚁的总数(编号分别为1~N)和记录的条数(1<=N,M<=1000)。紧接着有M行,每一行输入两个数字,a b,表示编号a和编号b的蚂蚁在同一堆里面。在每组测试案例之间都会输入一行空行。

Output

对于每组测试案例,在一行中输出答案。

【...】

跟之前相比区别在于Find函数写成递归的形式简短了很多(笑)。

【代码】

int pre[1005];int Find(int x){return pre[x]==x?x:pre[x]=Find(pre[x]);}void join(int x,int y){    x=Find(x),y=Find(y);    if(x!=y) pre[x]=y;}int main(){    int t; scanf("%d",&t);    for(int k=0;k

【带删除并查集】

上边的并查集主要是用到了增,那么提到删,比如说删除u和指向节点v之间的联系,我们可能会下意识的觉得只要使u重新指向自己即可,但是这种做法是不对的。在实际情况中,我们的并查集形成的树的形态都是不可预估形态的,如果直接将节点u指向自己,可能会将u的下级和u一块删除。所以需要处理一下:

定义一个数组f[]存放虚根,f[i]存放的是元素 i 的编号,这个编号在程序运行过程中是逐渐变化的。

当删除了 元素 i 以后,将元素 i 的编号更改为当前最大的编号+1(pos),再把pre[i]赋值为新的f[i]。
这样可以使得元素 i 原先的同组元素不受影响,且元素 i 被分配到一个只包含元素 i 的新组。

这里提到了一个虚根的概念,意思就是在删除节点u的时候,使节点u的虚根f[u]指向一个不存在的节点,而pre[u]不做改动,从而既删除了节点u,又不影响u的同组元素。

【例题】

【...】

居然RE了一发,懵了一下然后发现因为虚根最多可能到1e6,一开始开到1e5+5不够用,可能会数组越界。

【代码】

const int maxn=1e6+5;const int inf=0x3f3f3f3f;const int mod=1e9+7;int pre[maxn],f[maxn],vis[maxn];int pos;int Find(int x){return pre[x]==x?x:pre[x]=Find(pre[x]);}void join(int x,int y){x=Find(x),y=Find(y);if(x!=y) pre[x]=y;}void del(int x){    f[x]=pos;    pre[pos]=pos;    pos++;}int main(){    int n,m,t=0;    while(~scanf("%d%d",&n,&m))    {        if(n==0&&m==0) break;        pos=n;        for(int i=0;i

【关系并查集】

带关系的并查集。

【例题】

【题意】

输入恋爱关系,判断是否存在同性恋。

【代码】

#define go(i,a,b) for(int i=a;i<=b;i++)#define og(i,a,b) for(int i=a;i>=b;i--)#define mem(a) memset(a,0,sizeof(a))using namespace std;int pre[2005],r[2005],f;int Find(int x){    if(x==pre[x]) return x;    int t=Find(pre[x]); //寻找祖先    r[x]=(r[x]+r[pre[x]])%2;    return pre[x]=t;}void join(int x,int y){    int fx=Find(x),fy=Find(y);    if(fx==fy)    {        if(r[x]==r[y]) f=1;        return;    }    pre[fx]=fy;    r[fx]=(r[x]+r[y]+1)%2; //相邻不同性别}int main(){    int t; scanf("%d",&t);    while(t--)    {        f=0;        int n,m; scanf("%d%d",&n,&m);        go(i,1,n) pre[i]=i,r[i]=0;        while(m--)        {            int a,b; scanf("%d%d",&a,&b);            if(f) continue;            else join(a,b);        }        if(f) puts("Suspicious bugs found!");        else puts("No suspicious bugs found!");    }    return 0;}

 

转载地址:http://eyben.baihongyu.com/

你可能感兴趣的文章
理解TCP中的三次握手
查看>>
linux session 浅谈
查看>>
Emacs 中文学习手册-1
查看>>
Emacs学习笔记(1):初学者的学习计划
查看>>
Emacs学习笔记(13):在Emacs中打开pdf
查看>>
Emacs学习笔记(14):在Emacs中使用git
查看>>
Emacs for vim Users---from http://www.crazyshell.org/blog/
查看>>
静态库和动态库链接那些事--http://www.crazyshell.org/blog/?p=50
查看>>
一年成为Emacs高手(像神一样使用编辑器) .--http://blog.csdn.net/redguardtoo/article/details/7222501
查看>>
GNU make 指南
查看>>
配置 vim
查看>>
centos 安装emacs24
查看>>
【转】结构体中Char a[0]用法——柔性数组
查看>>
结构体最后定义一个char p[0];这样的成员有何意义(转)
查看>>
一步一学Linux与Windows 共享文件Samba (v0.2b)
查看>>
Linux 下忘记root密码怎么办
查看>>
Linux软件下载源码编程文章资料周立发--之调试
查看>>
GIT分支管理是一门艺术
查看>>
Cscope在emacs中的配置与使用
查看>>
emacs 2.4安装问题 ecb
查看>>