算是非常基础的内容了,之前写到Kruskal的时候突然想起还没整理过。
其实就想存个板子
并查集是一种树型的数据结构,用于处理一些集合(只能是不交集)。
“感性理解”一下就是把一堆东西分成若干堆,每个东西都在且仅在其中一堆里。
具体实现的话利用一个father数组,指向该元素的父亲节点。初始时所有元素的father均为它自己,表示每个元素均各自在自己的集合里。若两个元素在同一个集合中,它们的祖先就为同一个。
主要是两个函数:join和find。
先说一下find:
int find(int x) { if(father[x]!=x) father[x] = Find(father[x); return father[x]; }
很好理解,如果x是自己的父亲,它就是自己集合的根节点,否则就逐层查询到根节点为止(顺便路径压缩——把集合中的点都直接连在根节点下)。这个函数主要是用来通过看两个元素的祖先是否一致,判断两个元素是否在同一个集合中。
然后是join:
void Join(int x, int y){ int fx = Find(x), fy = join(y); if(fx != fy) father[fy] = fx; return; }
这里需要想象一下,假如要把两个很大的集合合并起来,最简单的操作就是直接把一个集合的根节点并到另一个集合下。(至于结构会很混乱嘛……下次Find的时候再整理就行了)
代码实现:
#include <bits/stdc++.h> using namespace std; int father[10010]; int Find(int x) { if(father[x]!=x) father[x]=Find(father[x]); return father[x]; } void Join(int x, int y){ int fx = Find(x), fy = join(y); if(fx != fy) father[fy] = fx; return; } int main() { for(int i=1; i<=10000; i++) father[i]=i; int n, m, x, y; scanf("%d %d", &n, &m); while(m--) { scanf("%d %d",&x,&y); Join(x, y); } int p; scanf("%d", &p); while(p--) { scanf("%d %d",&x,&y); if(Find(x) != Find(y)) printf("F "); else printf("T "); } return 0; }