树- 并查集
来源:互联网 发布:erp软件二次开发 编辑:程序博客网 时间:2024/06/08 11:36
POJ 2524 宗教信仰
#include <bits/stdc++.h>using namespace std;const int N = 5e4 + 8;int m, n, fx, fy, x ,y,cnt,tot;int f[N], nn[N];int find(int x){ return (x == f[x] ? f[x] : f[x] = find(f[x]));}void Union(int x, int y){ fx = find(x); fy = find(y); if(fx != fy) f[fx] = fy;}int main(){#ifndef ONLINE_JUDGE freopen("input.txt","r",stdin); freopen("output.txt","w",stdout);#endif scanf("%d%d",&n,&m); while(m != 0 && n != 0) { cnt = 0; for(int i = 1; i <= n; i++) f[i] = i; memset(nn,0, sizeof(nn)); for(int i = 1; i <= m; i++) { scanf("%d%d",&x,&y); Union(x,y); } printf("Case %d: ",++tot); for(int i = 1; i <= n; i++) { //printf("%d %d\n",i,f[i]); nn[find(i)]++; } for(int i = 1; i <= n; i++) { if(nn[i] != 0) cnt ++; } printf("%d\n",cnt); scanf("%d%d",&n,&m); }#ifndef ONLINE_JUDGE fclose(stdin); fclose(stdout);#endif}
裸的并查集 注意初始化即可。
POJ 1703 发现它 抓住它
描述
一个城市中有两个犯罪团伙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.
解题思路
利用保存了与父节点关系的并查集进行相应的操作
如果并不在一个并查集中说明现在他们之间的关系还不能确定
关注关系的维护
在每一次进行find操作的时候 由于我们会把f[x]更改为find(f[x]) 所以我们确定rel[x]的时候一定要先对f[x]执行find操作
#include <iostream>#include <string.h>using namespace std;int x,y,fx, fy,n,M;int T;const int N = 1e5 + 5;int f[N], rel[N];int find(int x){ if( x == f[x] ) return x; else{ int temp = find(f[x]); rel[x] = (rel[f[x]] + rel[x]) % 2; f[x] = temp;//一定要注意顺序的问题 一定要先对f[x]进行find操作 这样才能正确得到rel[f[x]]的值 } return f[x];}void Union(int x, int y){ fx = find(x); fy = find(y); if(fx != fy) { f[fx] = fy; if(rel[y] == 0) rel[fx] = 1 - rel[x]; else rel[fx] = rel[x]; }}int main(){#ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout);#endifscanf("%d",& T);while(T--){ scanf("%d%d",&n, &M); char ch[3]; for(int i = 1; i <= n; i++)f[i] = i, rel[i] = 0; for(int i = 1; i <= M; i++) { scanf("%s",ch); scanf("%d%d",&x,&y); if(ch[0] == 'A') { // printf("%d %d %d %d",x,y,find(x),find(y)); if(find(x) != find(y)) printf("Not sure yet.\n"); else { if(rel[x] == rel[y]) printf("In the same gang.\n"); else printf("In different gangs.\n"); } } else { Union(x,y); } }}#ifndef ONLINE_JUDGE fclose(stdin); fclose(stdout);#endif return 0;}
注意点:
一个是rel的维护
一个是初始化
一个是关于char输入时最好用ch[3]来避免读入换行等情况。
关于关系的维护 另一道类似的题目
POJ-1182 食物链
在考虑关系的时候容易出错,事实上,我们可以从向量的角度来考虑这个问题
注意点: 在查找的关系中,与其父节点的关系会发生变化 因为会实现路径压缩
rootx->rooty = rootx->x + x->y + y->rooty
完整代码实现
#include <iostream>using namespace std;const int Max = 5e4 + 8;int N, K;int D, x, y, fx, fy;int cnt;int f[Max], rel[Max];//f用来存放父亲(祖先) rel用来存放关系 如果是同类就存0 如果是x 吃f[x]存1 f[x] 吃x存2int find(int x){ if(f[x] == x) return x; int temp = 0; temp = find(f[x]); rel[x] = (rel[x] + rel[f[x]]) % 3; return f[x] = temp;}void Union(int x, int y, int D){ fx = find(x); fy = find(y); f[fx] = fy; rel[fx] = (3 - rel[x] + rel[y] + D - 1) % 3;}int main(){#ifndef ONLINE_JUDGE freopen("input.txt","r",stdin); freopen("output.txt","w",stdout);#endif scanf("%d%d",&N,&K); for(int i = 1; i <= N; i++) f[i] = i, rel[i] = 0; for(int i = 1; i <= K; i++) { //printf("N%d K%d\n",N,K); scanf("%d%d%d",&D,&x,&y); //printf("%d,%d,%d\n",D,x,y); if(x > N || y > N || (x == y && D == 2)) {cnt++; continue;} fx = find(x), fy = find(y); //-66666666printf("x:%d,y:%d,fx:%d fy:%d\n",x,y,fx,fy); if(fx == fy) { //printf("x:%d,y:%d,fx:%d,fy:%d,relx:%d,rely%d\n",x,y,fx,fy,rel[x],rel[y]); if((D== 1 && rel[x] != rel[y]) || (D == 2 && (rel[x] - rel[y]) % 3 != 1)) { // bug出现在这里 这里还是用向量的思想---- x->y = x->root + root->y ! cnt++; } continue; } else Union(x,y,D); //printf("x:%d,y:%d,fx:%d,fy:%d,relx:%d,rely%d\n",x,y,fx,fy,rel[x],rel[y]); } printf("%d\n",cnt);#ifndef ONLINE_JUDGE fclose(stdin); fclose(stdout);#endif}
总结
- 两种并查集
- 给出某两者属于同一并查集 只需要实现简单的维护和查询即可
- 带关系的并查集, 在同一个并查集中仅仅意味着两者关系可知
- 注意点
- 初始化
- 带关系的并查集
- 在路径压缩的过程中先对父节点进行find 再更新rel 否则得到的rel不是与根节点的关系
- 关于关心的更新和维护可以参考向量的概念!(以及记得取余数)
- 具体介绍(http://blog.csdn.net/niushuai666/article/details/6981689)
带关系的并查集的另一种解法:以食物链为例
维护3个并查集
http://blog.csdn.net/backforward/article/details/51892505
很神奇的想法了~
- 树- 并查集
- 并查集判断树
- 偶数树 并查集
- 10. 树--并查集
- 【bzoj4551】树 并查集
- HDU3938 并查集 并查集
- 并查集(集并查)
- HDU1232 并查集<并>
- POJ 2985 线段树+并查集
- Virtual Friends 字典树 并查集
- poj 2985 并查集 + 线段树
- pku1456贪心+并查集/线段树
- POJ 2513 Trie树+并查集
- poj 1308 并查集判断“树”
- hdu3172 字典树&&并查集
- 【并查集】判断是否为树
- hdu 3172 字典树+并查集
- hdu3172(字典树+并查集)
- 安卓中margin、algin、padding区别(图解)
- 时间复杂度详解
- MVC模式(一)
- C语言程序 显示当天日期
- 微信分享链接的缩略图和标题
- 树- 并查集
- ListView之Adapter的复用
- TensorFlow入门教程(3)
- Hadoop NameNode 高可用 (High Availability) 实现解析
- PyQt4-入门学习(2)
- 关键字
- Dialog、Toast的Window和ViewRootImpl
- unity 中 随机(伪随机) 数
- 使用IDEA创建一个Axis Sample