一、并查集
解决的问题类型:元素关系问题
总体分三部分:初始化(init)查(find)并(merge)
(1)简易的并查集
1、init()
创建一个一维数组,将下表作为当前关系人的编码,值为他的父节点。例如当前有N个人
int f[N+1];
for(int i=1;i<N+1;i++)f[i]=i;
2、find()
寻找当前这个人的 根 父节点
int my_find(int *f, int a)
{
if(f[a]==a)return a;
else return my_find(f,f[a]);
}
3、merge()
将a的根父节点改为b的根父节点
void meger(int *f,int a,int b)
{
f[find(f,a)]=find(f,b);
}
具体问题训练为:leetcode:886.可能的二分法
思路:
操作1: 先创建人数2倍的并差集数组f[2*n+1],将每一个人的父节点都设置为自身。
操作2: 然后创建a人与b人以及他们的父节点da=a+n与db=b+n。
操作3: 查找a与b人的根节点是否相同,相同则返回false;不同则合并。
注意:合并是
a的根节点的父节点设置为db的父节点
b的根节点的父节点设置为da的父节点
原因
将a不喜欢的人b都分到同一个da的父节点下
将b不喜欢的人a都分到同一个db的父节点下
#define MAX_BUF_LEN 5000
int find(int *f, int a)
{
if(f[a]==a)return a;
else return find(f,f[a]);
}
void meger(int *f, int a, int b)
{
f[find(f,a)] = find(f,b);
}
bool possibleBipartition(int n, int **dislikes, int dislikesSize, int* dislikesColSize){
int *f =malloc(sizeof(int)*(2*n+1));
//初始化并查集
//操作1
for(int i=1;i<2*n+1;i++)f[i]=i;
//操作2
int a,b,da,db;
for (int i = 0; i < dislikesSize; ++i){
a=dislikes[i][0];
b=dislikes[i][1];
da=a+n;
db=b+n;
//操作3
if(find(f,a)==find(f,b))return false;
meger(f,a,db);
meger(f,b,da);
printf("%d\n",a );
}
son //1 - 2 - 3 - 4 - 5 - 6 - 7 - 8
fater//1 - 2 - 3 - 4 - 5 - 6 - 7 - 8
relaition //1,2
//1 - 2 - 3 - 4 - 5 - 6 - 7 - 8
//(6)-(5)-3 - 4 - 5 - 6 - 7 - 8
//1 , 3
//1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 //1.f=6->6.f=6 3.f=3
//6 - 5 -(5)- 4 - 5 -(7)- 7 - 8//6.f=3+4 3.f=5
//2,4
//1 - 2 - 3 - 4 - 5 - 6 - 7 - 8//2.f=5->5.f=5 4.f=4
//6 - 5 - 5 -(7)-(8)- 7 - 7 - 8//5.f=4+4 4.f=(2+4).f=6.f=7
return true;
}
(2)优化并查集
在find()函数中,我们为了寻找到a1的根需要一直递归寻找,如果a2的父节点为a1,则寻找a2的根节点又重复了寻找a1的根操作,因此为了优化算法,我们将每一个数的父节点都指向他的根。
二、动态规划
有空再写