并差集的链表、路径压缩两种方法
来源:互联网 发布:淘宝认证复核 包过 编辑:程序博客网 时间:2024/05/18 01:51
Discription
若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。 规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。
Input
第一行:三个整数n,m,p,(n< =5000,m< =5000,p< =5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系。 以下m行:每行两个数Mi,Mj,1< =Mi,Mj< =N,表示Mi和Mj具有亲戚关系。 接下来p行:每行两个数Pi,Pj,询问Pi和Pj是否具有亲戚关系。
Output
P行,每行一个’Yes’或’No’。表示第i个询问的答案为“具有”或“不具有”亲戚关系。
算法
算法需要以下几个子过程:
(1) 开始时,为每个人建立一个集合SUB-Make-Set(x);
(2) 得到一个关系后a,b,合并相应集合SUB-Union(a,b);
(3) 此外我们还需要判断两个人是否在同一个集合中,这就涉及到如何标识集合的问题。我们可以在每个集合中选一个代表标识集合,因此我们需要一个子过程给出每个集合的代表元SUB-Find-Set(a)。于是判断两个人是否在同一个集合中,即两个人是否为亲戚,等价于判断SUB-Find-Set(a)=SUB-Find-Set(b)。
有了以上子过程的支持,我们就有如下算法。
PROBLEM-Relations(N, M, a1,…,aM, b1,…,bM, Q, c1,…,cQ, d1,…,dQ)
1 for i←1 to N
2 do SUB-Make-Set(i)
3 for i←1 to M
4 do if SUB-Find-Set(ai) != SUB-Find-Set(bi)
5 then SUB-Union(ai, bi)
6 for i←1 to Q
7 do if SUB-Find-Set(ci)=SUB-Find-Set(di)
8 then output “Yes?”
9 else output “No?”
单链表实现
一个节点对应一个人,在同一个集合中的节点串成一条链表就得到了单链表的实现。在集合中我们以单链表的第一个节点作为集合的代表元。于是每个节点x(x也是人的编号)应包含这些信息:指向代表元即表首的指针head[x],指向表尾的指针tail[x],下一个节点的指针next[x]。
SUB-Make-Set(x)过程设计如下:
SUB-Make-Set(x)
10 head[x]←x
11 tail[x]←x
12 next[x]←NIL
求代表元的SUB-Find-Set(x)过程设计如下:
SUB-Find-Set(x)
13 return head[x]
前两个过程比较简单,SUB-Union(a,b)稍微复杂一点。我们要做的是将b所在链表加到a所在链表尾,然后b所在链表中的所有节点的代表元指针改指a所在链表的表首节点,如图所示。
图0-0-2
过程的伪代码如下:
SUB-Union(a,b)
14 next[tail[head[a]]]←head[b]
15 tail[head[a]]←tail[head[b]]
16 p←head[b]
17 while p != NIL
18 do head[p]←head[a]
19 p←next[p]优化——路径压缩
思想
每次查找的时候,如果路径较长,则修改信息,以便下次查找的时候速度更快。
实现
第一步,找到根结点。
第二步,修改查找路径上的所有节点,将它们都指向根结点。#include <iostream>using namespace std;int father[50002],a,b,m,n,p;int find(int x){ if(father[x] != x) father[x] = find(father[x]); /*x代表例题中的人,都与一个人有亲戚关系,相当于例题中第一个集合所有的元素都与第一个元素有亲戚关系,搜索时只要找元素所指向的father[x]=x的元素(即父元素),然后比较两个元素的父元素是否相同就可以判断其关系*/ return father[x]; //也可以修改成 return father[x] == x ? x : father[x] = find(father[x]);}int main(){ int i; scanf("%d%d%d",&n,&m,&b); for(int i = 1;i <= n;i++) father[i] = i; for(i=1;i<=m;i++){ scanf("%d%d",&a,&b); a=find(a); b=find(b); father[a]=b;}for(i = 1;i <= p;i++){ scanf("%d%d",&a,&b); a = find(a); b = find(b); if(a == b) printf("Yes\n"); else printf("No\n");} return 0;}
- 并差集的链表、路径压缩两种方法
- 【模板】并查集 两种路径压缩写法
- 并查集的两种优化(按秩合并,路径压缩)
- POJ2524 并差集以及优化(路径压缩+按秩合并)的简洁介绍
- 并查集路径压缩方法
- 并查集及其路径的压缩
- 转载 并查集的路径压缩。
- 并查集的路径压缩算法
- 并查集的路径压缩
- 并查集及并查集的路径压缩
- 并查集 & 路径压缩
- 【并查集+压缩路径】
- 并查集路径压缩
- 并查集路径压缩
- 并查集路径压缩
- 并查集路径压缩
- 并查集压缩路径
- 并查集 压缩路径
- Spring MVC入门介绍
- 腾讯编程题:构造回文
- IIS7.0 Appcmd 命令详解
- Codeforces Round #360 (Div. 2) ABCDE题解
- vim 树形目录插件NERDTree安装及简单用法
- 并差集的链表、路径压缩两种方法
- GDB no such file or directory
- 选中自然语言处理任务的连续表达
- ovirt中无法创建ISO-NFS问题
- 设计模式之结构型模式
- Vim试水之六:NerdTree插件安装
- daterangepicker的时间参数问题
- bp神经网络
- CRF 简介入门 .