算法训练--并查集

/*
给定n个变量和m个约束,判定是否能找出一种赋值方案满足这m个约束条件
*/
//n:如题意
//m:如题意
//A:大小为m的数组,表示m条约束中的a
//B:大小为m的数组,表示m条约束中的b
//E:大小为m的数组,表示m条约束中的e
/* 并查集解决 */
const int N = 300005;
//Father:每个节点的父亲节点
//Rank:节点的秩
int Father[N],Rank[N];

//查找结点X所在的根
//x:节点x
int find(int x){
if(Father[x] != x)
return x;
Father[x] = find(Father[x]);
return Father[x];
}

string getAnswer(int n,int m,vector<int> A,vector<int> B,vector<int> E){
//初始化
for(int i = 0;i <= n; ++i){
Father[i] = i;
Rank[i] = 0;
}
int cnt = 0;
for(int i=0;i < m; ++i){
if(E[i] == 1){
swap(A[i],A[cnt]);
swap(B[i],B[cnt]);
swap(E[i],E[cnt]);
++cnt;
}
}
for(int i = 0;i < m; ++i){
int setA = find(A[i]);//找到A[i]所在集合的根
int setB = find(B[i]);//找到B[i]所在集合的根
if(E[i] == 0){
//如果setA == setB,说明A[i]和B[i]在同一棵树中,
//而本身两者不应该存在关系,所以此时这种情况不存在
if(setA == setB){
return "No";
}
} else{//setA,setB 是一个数字
//当A[i]和B[i]存在关系,并且两者所在的树的根不同时,说明两者分别属于
//不同的树,此时是可以进行合并的;
if(setA != setB){
//合并的要求是判断两棵树的大小,原则上是小树作为大树的子树

if(Rank[setA] > Rank[setB])
//始终将小的放在setA中,大的放在setB中
swap(setA,setB);
//根据判断结果, 将setA归置在setB中
Father[setA] = setB;
//若setA,setB相同,则说明两者在同一棵树中,将setB的秩增加
//其实我觉得在这应该就是setB所在的树的高度+1,因为
if(Rank[setA] == Rank[setB])
Rank[setB] += 1;
}
}
}
return "Yes";
}

 并查集讲解:https://blog.csdn.net/dm_vincent/article/details/7655764

posted @ 2018-11-16 22:57  Lyon刘  阅读(191)  评论(0编辑  收藏  举报