并查集及其优化
总结一下并查集吧。
学了好多次结果都没记住。
啊~~~~~~
下面介绍一个我比较看得过去的并查集入门介绍
下面是他给出的一个代码模板
#include <iostream>
using namespace std;
const int N = 10010;
int f[N];
int high[N]; // 保存每个朋友圈的高度,初始时都是 0
/*
* 将表示朋友圈的数组初始化,即将所有人的“朋友祖先”都设置为自己的 id ,
* 于是就有了 n 个不同的朋友圈
*/
void init(int n)
{
for(int i = 1; i <= n; i++)
{
f[i] = i;
}
}
// 得到 id 为 v 的人的“朋友祖先”的 id
int getFriend(int v)
{
if(f[v] == v)
{
return v;
}
/*
* 如果发现“朋友祖先”不是自己,那么他肯定被合并到别的朋友圈里面去了,
* 那么继续调用这个函数来找这个朋友圈里面的“朋友祖先”,
* 并且在这个过程中将找到的人都设置为同一个“朋友祖先”(因为都在同一个朋友圈里面)
*/
return f[v] = getFriend(f[v]);
}
/**
* 将两个人所在的两个朋友圈合并为一个朋友圈
* 这里通过两个朋友圈的高度来决定合并方式
*/
void merge(int a, int b)
{
int t1 = getFriend(a); // 得到左边的人的“朋友祖先”
int t2 = getFriend(b); // 得到右边的人的“朋友祖先”
// 两个人的“朋友祖先”不一样,合并两个朋友圈
if(t1 != t2) {
// 如果左边的朋友圈的高度大于右边的朋友圈的高度,
// 那么将右边的朋友圈合并到左边的朋友圈中
if (high[t1] > high[t2])
{
f[t2] = t1;
// 否则就把左边的朋友圈合并到右边的朋友圈中
}
else
{
f[t1] = t2;
// 如果当前两个朋友圈的高度相等,那么合并之后的朋友圈高度要加1
if (high[t1] == high[t2])
{
high[t2]++;
}
}
}
}
int main()
{
int n, m, k;
cin >> n >> m >> k;
int x, y;
init(n);
for(int i = 0; i < m; i++)
{
cin >> x >> y;
merge(x, y);
}
/*
* 输出合并之后的数组情况
*/
for(int i = 1; i <= n; i++)
{
if(i != 1)
{
cout << " ";
}
cout << f[i];
}
cout << endl;
for(int i = 0; i < k; i++)
{
cin >> x >> y;
// 如果两个人的“朋友祖先”不相同,证明他们不在同一个朋友圈内,也就不是朋友
if(getFriend(x) != getFriend(y))
{
cout << "no" << endl;
}
else
{
cout << "yes" << endl;
}
}
return 0;
}
上面的代码是针对特定题目的,而且注释巨多。
下面我总结一个比较简洁的代码模板吧,
我也借机熟悉一下代码,嘿嘿~
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010;
int f[maxn];//每个节点的父节点
int high[maxn];//每个节点下属节点的高度(注意是高度不是个数)
void Init()//初始化函数
{
memset(high,0,sizeof(high));
for(int i=0;i<maxn;i++) f[i]=i;
}
int GetSet(int p)//获得p节点的根节点
{
return (f[p]==p)? p : GetSet(f[p]);
}
void Merge(int x,int y)//x与y集合合并
{
x = GetSet(x);
y = GetSet(y);
if(x != y)
{
if(high[x]>high[y])
{
f[y]=x;
}
else
{
f[x]=y;
if(high[x]==high[y])high[y]++;
}
}
}
//这里是主函数
int main()
{
int n, m, k;
cin >> n >> m >> k;
int x, y;
Init();
for(int i = 0; i < m; i++)
{
cin >> x >> y;
Merge(x, y);
}
//输出合并之后的数组情况
for(int i = 1; i <= n; i++)
{
if(i != 1) cout << " ";
cout << f[i];
}
cout << endl;
for(int i = 0; i < k; i++)
{
cin >> x >> y;
//如果两个人的“朋友祖先”不相同,证明他们不在同一个朋友圈内,也就不是朋友
if(GetSet(x) != GetSet(y)) cout << "no" << endl;
else cout << "yes" << endl;
}
return 0;
}
给一个测试数据
7 5 4
1 3
2 4
3 4
1 4
5 6
1 4
2 3
2 5
6 7
结果如下
4 4 4 4 6 6 7
yes
yes
no
no
OK