并查集和最小生成树的总结

关于并查集和最小生成树的总结

 

先说下并查集,并查集字如其名,实现的功能就是并和查,并查集的实现主要就是两个函数,一个合并函数UnoinSet()和查找函数find(),另外并查集也可以进行优化,find()函数里进行路径压缩,UnoinSet()函数里可以进行按秩合并。

优化后的find():

 

int find(){
         if(par[x]== x)
                  returnx;
         returnpar[x] = find(par[x]);
}

 

 

 

 

 

优化后的UnoinSet():

 

void UnoinSet(){
         intx = find(u);
         inty = find(v);
 
         If(x!= y){
                  If(rank(x)> rank[y])
                          par[y]= x;
                  else{
                          par[x]= y;
                          if(rank[x]== rank[y])
                                   rank[y]++;
			}
		}
}

 

 

 

 

 

下面来总结一下关于并查集的题目,首先是poj1182 食物链这道题目,这道题目利用到的知识点是并查集+向量偏移。所谓的向量偏移就是利用了向量的加减法,先来说一下这道题目的理解,delta[]数组来记录偏移量,delta[i]表示从根节点到当前结点i的偏移量,假设输入d,a,b,分别表示关系和动物ab,其根节点分别为fa,fb,当fa!=fb时,现在假设把fb合并到fa上面,fa->fb= fa->a + a->b + b –>fb,进一步可以转化为fa->fb=(delta[a] + b-1 – delta[b]+3)%3=delta[fb],模3的目的是为了让结果都在[0,2]之间。当fa==fb是,a->b=a->fa+fa->b,即判断d-1是否等于(-delta[a] + 3 + delta[b])%3。

关于这一类的题目的重点就是推导出集合之间的关系,然后通过向量来解决。

下面来说下poj1988 这道题目,这道算是并查集+递归,难点主要在于递归式的推导。也就是每次递归计算从该节点到根节点的距离。

还有就是poj1308,poj2254这两道题目就不在此多讲了。

 

 

下面来说说关于最小生成树的一些理解吧,之所以放在并查集后面来讲,是因为克鲁斯卡尔算法是利用并查集来实现的,理解了并查集后再理解这个算法就简单多了。

首先来说prim算法,和dijkstra算法十分类似,假设当前到达的最小权值的顶点是k,区别就在于跟新最短路径的时候,prim更新的是dis[j]与map[k][j]之间的关系,当然最重要的是prim算法有也有堆优化(PS:现在还没能掌握);prim算法更适用于稠密图,克鲁斯卡尔算法更适用稀疏图。

Poj1679 判断最小生成树是否唯一。

Poj1251 把字符串转换成数组下标求解

Poj1751,poj1789,先求出个点之间的权值,然后求最小生成树

Poj2377 求最大生成树

Poj2395 求最小生成树的最大边

Poj3625 不是很难的一道题目,要注意c++提交double输出%lfG++提交double输出%f

在这里说下poj1679判断最小生成树唯一的问题,如果一个最小生成树中有n个顶点,则有n-1条边,在利用克鲁斯卡尔算法判断时,首先对所有边排序,然后选择边,这时只要判断选择的的n-1条边之前和之后与其相等的边即可,判断第n-1条边之后的边是否能够替换前面的边,只要存在顶点相等即可替换;

你可能感兴趣的:(ACM)