带权并查集

似乎好些天没写文章了,感慨万千啊。

一如既往,先介绍一下题目的需求吧,如下:

题目简述:某人想编写一个字典,该字典中存在正反两种关系,并且这种关系具有某种规则下的传递性质,如下:

A 与 B 同义, B 与 C 同义,则 A 与 C同义 ;

A 与 B 同义, B 与 C 反义,则 A 与 C反义 ;

A 与 B 反义, B 与 C 同义,则 A 与 C反义 ;

A 与 B 反义, B 与 C 反义,则 A 与 C同义 。

此人最初定义部分字符串的正反关系,要求以此为基础将所有给定字符串之间的关系进行完善,并且在给出两个字符串的时候能够判断出两者关系。

首先在分析输入输出之前对要求进行分析,题目给定部分字符串,由需求可知能与某字符串发生关系,就会与其所在的关系中任何一个字符串发生关系,由此可知,建立起来的图是完全连通图,图中每两个节点之间都有其表示关系的权值。观察题目,可以发现题目中给定的信息只有字符串和两字符串的关系,除此之外没有其他信息,也就意味着只需要对这两个信息进行操作,维护其中的关系即可。并查集解决的是完全连通图基础上的问题,在此基础上延伸出的带权并查集处理的是节点之间有权值的完全连通图的问题。将本题稍作变通即可用带权并查集方法,这种特殊的处理就是将两个字符串之间的关系用两个字符串到其所在集合代表元素关系来间接表示(关系的传递性可以确保实现的可能)。

接下来,从输入输出信息对细节进行处理,输入数据说明如下:

输入数据给出字典中字符串的个数 n 、预设关系的个数 m 、待判断字符串的对数 q ,以及 m 对预设关系和 q 对待判断的字符串。

输出数据要求如下:

要求按照预设信息建立字典,输出待查询两个字符串之间的关系。其中正关系用 1 表示,反关系用 2 表示 ,若关系不明用 3 表示。


建立并查集的 father数组(存放当前节点所在集合代表元素编号) 和 dist数组(存放当前节点到所在集合表表元素的关系) 时,需要用编号对所有字符串唯一标记,方便与 father 数组 和 dist 数组中的各元素唯一对应。此时用string类型的数组存储便可以完成,用某个字符串在string数组中存放的位置来表示该字符串即可,这么做有一个缺点,在判断两个字符串的关系的时候需要遍历整个数组找到两个字符串并确定两个字符串的关系,这时候进一步思考可以发现存储映射关系是 map 的强项,用 map 存储就可以更有效的完成查找字符串的编号这个需求。


先插入带权并查集基本知识:

带权并查集,是在普通并查集的基础上,给每个元素赋予了特定的权值,该权值表现了当前元素到代表元素(根节点)的某种特定关系,例如亲缘关系等,并且这种关系是有向的。在合并的过程中,相应的也要改变当前元素到代表元素的关系,由于关系是有向的,因此运算应该遵守矢量运算法则。在这个过程中,每个元素到其根节点的关系用 dist[]数组来表示,

如下:

当前已知 a 的根节点是 ra,a 到 ra 的关系是 dist[a],b 的根节点是 rb ,b 到 rb 的关系是 dist[ b],且 b 到 a 的关系是 x ,这时候,合并 ra 和 rb 的过程中,dist 数组处理为 :

dist[ rb ]= x +dist[a]-dist[b];

实现如下:


对于字符串关系的存储和维护,在本题中,我将正关系定义为 0 ,反关系定义为 1 。运用上述思想,用 dist 数组中存储的数据表示当前节点到所在集合代表元素的关系。题目中特殊要求在进行字典建立的过程中,每输入一对关系,判断给定的关系之前是否已经建立,未建立或者已建立且所给关系吻合输出YES ,已建立但与所给的关系不吻合输出 NO ,因此在合并的实现中需要对这个需求进行处理。

在两字符串的关系判断环节,同一集合中的两个元素满足如下关系:

已知 A 为集合的代表元素,要求 B 与 C 的关系,由矢量法则可知 

dist[BC]= dist[BA]-dist[CA]。


主要思路如上,具体代码实现有兴趣的朋友可以打开网页http://paste.ubuntu.com/24505408/。

原文地址:https://www.cnblogs.com/detrol/p/7533603.html