并查集
并查集是一种只关心元素对于集合的所属关系的数据结构。
它的原型是一棵树,使用 “父亲表示法” 表示,用数组 Fa[i] 保存 i 的父亲的编号。
每个孩子都有一个父亲,而一个家族的祖先便是这个家族的标识。
如果你我有着同样的祖先,则你和我是一个家族的。
特别的,祖先的父亲是自己。
并查集善于添加关系。
如果涉及到破化关系,可以考虑反向建边。
\(\sf\hspace{5cm}-David\)
\(\color{lightgray}\textsf{2023-1-31 Updated}\)
一般的并查集
初始化
先认为每个元素自成集合,即 Fa[i]=i ,并集的时候在把父亲设为目标集合的祖先。
找父亲
由于并查集只关心所属关系,所以我爸是你或你爸是我没什么区别。所以,我们在找祖先时可以做路径优化,就是忽略之前所有的父子关系,统一认为一个家族所有人都是这个家族祖先的直接孩子,包括祖先自己。
使用递归函数向上找父亲、祖父、曾祖父……
回溯的时候顺便把父亲的父亲设为找到的那个祖先。
int Find(int n)
{
if(Fa[n]!=n) Fa[n]=Find(Fa[n]);
return Fa[n];
}
并集
只需要操作一下祖先即可。
void Merge(int a,int b)
{
a=Find(a),b=Find(b);
Fa[b]=a;
}
查集
如果你我有着同样的祖先,则你和我是一个家族的。
bool Judge(int a,int b)
{
a=Find(a),b=Find(b);
return (a==b);
}
拓展域并查集
有些时候,
我们不仅知道某些与某些在一个集合中,
我们还知道某些与某些不在一个集合中,
甚至知道某些和某些在相邻的两个集合中。
怎么办呢?
这个时候,我们就要请出“反我”了。
让我和“反我”始终不在一个集合之中,如果知道某某与我不在一个集合之中,就说明此某与“反我”在一个集合,我与“反此某”在同一集合中。
就巧妙地转化了问题。
封装一下?
正常并查集
template<int maxlength>
class DisjointSets
{
private:
int Fa[maxlength+5];
public:
DisjointSets()
{
for(int i=0;i<maxlength;i++)
Fa[i]=i;
}
DisjointSets(DisjointSets<maxlength>&m)
{
for(int i=0;i<maxlength;i++)
Fa[i]=m.Fa[i];
}
~DisjointSets(){}
int Find(int n)
{
if(n<0||n>=maxlength)
return -1;
if(Fa[n]!=n)
Fa[n]=Find(Fa[n]);
return Fa[n];
}
void Merge(int a,int b)
{
if(a<0||a>=maxlength||b<0||b>=maxlength)
return;
Fa[Find(b)]=Find(a);
return;
}
bool Judge(int a,int b)
{
if(a<0||a>=maxlength||b<0||b>=maxlength)
return false;
return Find(a)==Find(b);
}
void operator=(DisjointSets m)
{
for(int i=0;i<maxlength;i++)
Fa[i]=m.Fa[i];
}
int& operator[](int i){return Fa[i];}
};
拓展域并查集
template<int maxlength,int extent>
class ExjointSets
{
private:
int Fa[extent*maxlength+30];
int get(int x,int y){return x*maxlength+y;}
int find(int n)
{
if(Fa[n]!=n)
Fa[n]=find(Fa[n]);
return Fa[n];
}
void merge(int a,int b){Fa[find(b)]=find(a);return;}
bool judge(int a,int b){return find(a)==find(b);}
public:
ExjointSets()
{
const int amount=extent*maxlength;
for(int i=0;i<amount;i++)
Fa[i]=i;
}
ExjointSets(ExjointSets<maxlength,extent>&m)
{
const int amount=extent*maxlength;
for(int i=0;i<amount;i++)
Fa[i]=m.Fa[i];
}
~ExjointSets(){}
int Find(int n,int a)
{
if(n<0||n>=maxlength||a<0||a>=extent)
return -1;
return find(get(a,n));
}
void Merge(int a,int b,int dif)
{
if(a<0||a>=maxlength||b<0||b>=maxlength)
return;
if(dif<0||dif>=extent)
return;
for(int i=0;i<extent;i++)
merge(get(i,a),get((i+dif)%extent,b));
return;
}
bool Judge(int a,int b,int dif)
{
if(a<0||a>=maxlength||b<0||b>=maxlength)
return false;
if(dif<0||dif>=extent)
return false;
return judge(get(0,a),get(dif,b));
}
};
PCwqyy

浙公网安备 33010602011771号