本质
查询两个元素是否属于同一类
比较形象的是亲戚,A是B的爸爸,B是C的爸爸,问A与C是否有关系;
也可以是城市道路,有1,2,3这三个城市,有道路1 - 2,2 - 3,问1城市能否到达3城市;
样例
第一行包含两个整数N、M,表示共有N个元素和M个操作。
接下来M行,每行包含三个整数Zi、Xi、Yi
当Zi=1时,将Xi与Yi所在的集合合并
当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y;否则话输出N;
4 7 2 1 2 1 1 2 2 1 2 1 3 4 2 1 4 1 2 3 2 1 4
朴素代码
#include <bits/stdc++.h> using namespace std; const int N = 100001; int n,m; int fa[N]; int find(int x){ return fa[x] == x ? x : find(fa[x]); } void uni(int x, int y){ fa[find(x)] = find(y); } int ask(int x, int y){ return find(x) == find(y); } int main(){ cin >> n >> m; for(int i = 1; i <= n; ++i) fa[i] = i; // 最开始只和自己有关系 for(int i = 1, x, y, z; i <= m; ++i){ cin >> z >> x >> y; if(z == 1) uni(x, y); else ask(x, y) == true ? printf("Y ") : printf("N "); } return 0; }
优化
- 路径压缩
- 按秩合并
路径压缩
如果我们只考虑他们祖先,不考虑各个之间的具体关系,就可以在find函数里加个优化
代码
int find(int x){ return fa[x] == x ? x : fa[x] = find(fa[x]); }
按秩合并
就是小的连大的上,需要一个辅助数组size记长度
void merge(int x,int y){ int xx=find(x),yy=find(y); if(size[xx]<size[yy])swap(xx,yy); fa[yy]=xx;size[xx]+=size[yy]; }