并查集:
1.将两个集合合并
2.询问两个元素是否在一个集合之中。
基本原理:
每一个集合用一棵树表示。树根的编号就是整个集合的编号。每个结点存储它的父节点,p[x]表示x的父节点。
问题1:如何判断数根:
if (p[x] == x)
问题2:如何求x集合的编号:
int Find(int x)
{
if (x != p[x] ) p[x] = Find(p[x]);
return p[x];
}
问题3:如何合并两个集合
void Join(int x, int y )
{
int fx = Find(x), fy = Find(y);
if (fx != fy) p[fx] = fy;
}
等权并查集:
x的根节点将y的根结点作为父节点。左右两侧距离相等得出fx到fy距离
int Find(int x)
{
if(x != p[x])
{
int t = Find(p[x]);
d[x] += d[p[x]];
p[x] = t;
}
return p[x];
}
bool join(int x, int y)
{
int fx = Find(x), fy = Find(y);
if(fx == fy)
{
if(abs(d[x] - d[y]) % 2 != 1) return false ;
}
else if(fx != fy)
{
p[fx] = fy;
d[fx] = d[y] - d[x] + 1;
}
return true;
}
判断总集合个数 :
例题:Codeforces-445B DZY Loves Chemistry
代码如下:
# include <stdio.h>
# include <math.h>
int p[51];
int find(int x)
{
if(x != p[x])
p[x] = find(p[x]);
return p[x];
}
int main()
{
int n, m, a, b;
while(~scanf("%d%d",&n,&m))
{
int road = 0;
for(int i=0; i<=n; ++i)
p[i] = i;
while(m--)
{
scanf("%d%d",&a,&b);
int fx = find(a);
int fy = find(b);
if(fx != fy)
{
++road;
p[fx] = fy;
}
}
printf("%.0f\n",pow(2,road));
}
return 0;
}