描述
一个城市中有两个犯罪团伙A和B,你需要帮助警察判断任意两起案件是否是同一个犯罪团伙所为,警察所获得的信息是有限的。假设现在有N起案件(N<=100000),编号为1到N,每起案件由团伙A或团伙B所为。你将按时间顺序获得M条信息(M<=100000),这些信息分为两类:
1、 D [a] [b]
其中[a]和[b]表示两起案件的编号,这条信息表明它们属于不同的团伙所为
2、A [a] [b]
其中[a]和[b]表示两起案件的编号,这条信息需要你回答[a]和[b]是否是同一个团伙所为
注意你获得信息的时间是有先后顺序的,在回答的时候只能根据已经接收到的信息做出判断。
输入
第一行是测试数据的数量T(1<=T<=20)。
每组测试数据的第一行包括两个数N和M,分别表示案件的数量和信息的数量,其后M行表示按时间顺序收到的M条信息。
输出
对于每条需要回答的信息,你需要输出一行答案。如果是同一个团伙所为,回答”In the same gang.”,如果不是,回答”In different gangs.”,如果不确定,回答”Not sure yet.”。
- 样例输入
- 1
- 5 5
- A 1 2
- D 1 2
- A 1 2
- D 2 4
- A 1 4
- 样例输出
- Not sure yet.
- In different gangs.
- In the same gang.
我们先来讲一下这道题的思路,我们输入之后,首先将1~N这N个数字插入到并查集中,然后如果输入的是‘D’,那么就unionSet进行合并(一个集合内的所有元素代表这些犯罪团伙都不是一个团伙),如果输入的是‘A’,那么进行find函数查找a和b的所在集合,我们就只需要判断他们的所在集合是否相同即可。
如果不相同,代表不确定,输出Not sure yet.,如果a和b的父节点是相同的(代表他们是否是同一个集合),如果相同,就输出In the same gang.,如果不是就输出In different gangs.。
并查集和路径压缩算法的应用:
1、 father[i] 表示 i 的父节点是谁; relation[i] 表示 i 这个节点和他父节点的关系,0表示同一个犯罪组织,1表示不同。
2、初始化将每个节点的父节点赋值为自身, relation 也理所当然的赋值为0(相同)。
3、 Find(int x) 函数返回值为 x 的祖先。采用路径压缩。由于是递归,途中不断将这条路上上面节点接到祖先节点,并一路修改 relation 的值,直到最下面的节点接到祖先节点。
(1)如果 x 的父节点就是祖先节点,那么 father[x] 的 r 为 0,x 的 r 不需要改变;
(2)否则,有几种情况:
·r[ f[x] ] = 1,r[x] = 1,即 x 和他父亲不同,x 父亲和 x 父亲的父亲(祖先)也不同,所以 x 和 祖先相同
·r[ f[x] ] = 1,r[x] = 0,即 x 和他父亲不同,x 父亲和 x 父亲的父亲(祖先)相同,所以 x 和 祖先不同
·r[ f[x] ] = 0,r[x] = 1,即 x 和他父亲相同,x 父亲和 x 父亲的父亲(祖先)不同,所以 x 和 祖先不同
·r[ f[x] ] = 0,r[x] = 0,即 x 和他父亲相同,x 父亲和 x 父亲的父亲(祖先)也相同,所以 x 和 祖先相同
所以总结后有这样一个公式: r[x] = (r[x] + r[ f[x] ]) % 2;
4、输入命令时,如果是 D,表示这两个案件是不同团伙所做,那么把 x 的祖先归并到 y 的祖先下面,并修改 relation的值。由于查找祖先节点时,有路径压缩过程,所以归并时 x 已经直接接到他的祖先节点上。
由于 x 和 y 的种类不同,考虑如下情况:
(1)若 y 和 y 的祖先节点 fy 相同, r[y] = 0;则 x 和 fy不同。若 r[x] = 1, x 和 fx 不同,则 fx 和 fy 相同,
即 r[fx] = 0;同理可得当 r[x] = 0,r[fx] = 1;所以 r[fx] = 1 - r[x];
(2)若 y 和 fy 不同,同上分析,可得 r[fx] = r[x].
- #include
- using namespace std;
- template<class T>
- struct DisjointSet{
- int *parent;
- T *data;
- map
int> m; - int capacity;
- int size;
- DisjointSet(int max=1000){
- capacity=max;
- size=0;
- parent=new int[max+1];
- data=new T[max+1];
- }
- ~DisjointSet(){
- delete [] parent;
- delete [] data;
- }
- bool insert(T x){
- if(size==capacity) return false;
- size++;
- data[size]=x;
- parent[size]=-1;
- m[x]=size;
- return true;
- }
- int getIndex(T x){
- for(int i=1;i<=size;i++)
- if(data[i]==x)
- return i;
- return -1;
- }
- int find(T x){
- typename map
int>::iterator it; - it=m.find(x);
- if(it==m.end()) return -1;
- int i,rt;
- i=rt=it->second;
- while(parent[rt]>0)
- rt=parent[rt];
- return rt;
- }
- void unionSet(T x,T y){
- int rx,ry;
- rx=find(x);
- ry=find(y);
- if(rx==-1||ry==-1) return ;
- if(rx==ry) return ;
- if(parent[rx]
- parent[rx]+=parent[ry];
- parent[ry]=rx;
- }
- else{
- parent[ry]+=parent[rx];
- parent[rx]=ry;
- }
- find(x);
- find(y);
- }
- };
- int main(){
- int t;
- cin>>t;
- while(t--){
- DisjointSet<int> s;
- int n,m;
- cin>>n>>m;
- for(int i=1;i<=n;i++) s.insert(i);
- for(int i=1;i<=m;i++){
- int a,b;
- char c;
- cin>>c>>a>>b;
- if(c=='D')
- s.unionSet(a,b);
- else{
- if(s.find(a)!=s.find(b)) cout<<"Not sure yet.";
- else if(s.parent[a]==s.parent[b]) cout<<"In the same gang.";
- else cout<<"In different gangs.";
- cout<
- }
- }
- }
- return 0;
- }
这是一道并查集的经典题目,希望大家掌握。
该题链接:
OpenJudge - 3:发现它,抓住它
http://dsalgo.openjudge.cn/retrieval/3/
-
相关阅读:
制造业质量管理如何实现数字化?
Jenkins CVE-2017-1000353远程代码执行漏洞复现
计算机毕业设计ssm达梦商城-跨平台多商户电商平台nc9f0系统+程序+源码+lw+远程部署
kkfileview在docker部署后预览出现预览中的字体样式与源文件不同的解决办法
信息化发展56
线性代数学习笔记6-2:行列式的理解、行列式的性质
柯桥学俄语|商务俄语двое型与оба (обе) 型集合数词用法攻略
查看docker run 时启动命令
CSS 两栏布局
Linux下七种文件类型、文件属性及其查看方法
-
原文地址:https://blog.csdn.net/wo_ai_luo_/article/details/127231733