简体   繁体   English

Union + Find算法(不相交集)的应用

[英]Application of Union+Find algorithm(Disjoint Set)

Problem Statement: 问题陈述:

Equations are given in the format A / B = k , where A and B are variables represented as strings, and k is a real number (floating point number). 方程以A / B = k的形式给出,其中AB是表示为字符串的变量,而k是实数(浮点数)。

Given some queries, return the answers. 给定一些查询,返回答案。 If the answer does not exist, return -1.0. 如果答案不存在,则返回-1.0。

Example: Given a / b = 2.0, b / c = 3.0. 示例:给定a / b = 2.0, b / c = 3.0.

queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? 查询是: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? return [6.0, 0.5, -1.0, 1.0, -1.0 ] 返回[6.0, 0.5, -1.0, 1.0, -1.0 ]

The input is: 输入为:

vector<pair<string, string>> equations
vector<double>& values
vector<pair<string, string>> queries 

where equations.size() == values.size() , and the values are positive. 其中equations.size() == values.size() ,并且值是正数。

This represents the equations. 这表示方程式。

Return vector<double> . 返回vector<double>

According to the example above: equations = [ ["a", "b"], ["b", "c"] ] 根据上面的示例:equations = [ ["a", "b"], ["b", "c"] ]

values = [2.0, 3.0] 值= [2.0, 3.0]

queries = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ] 查询= [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ]

The input is always valid. 输入始终有效。 You may assume that evaluating the queries will result in no division by zero and there is no contradiction. 您可以假设对查询进行评估将不会导致被零除,并且没有矛盾。

Solution This can be solved using Union+Find on disjoint set, a solution is seen here: 解决方案这可以通过对不交集使用Union + Find来解决,在这里可以看到一个解决方案:

Solution

However, I'm not clear on the intuition behind line 59: 但是,我不清楚第59行背后的直觉:

rst[i] = uf.rank.get(queries[i][0]) / uf.rank.get(queries[i][1]);

As well as line 99: 以及第99行:

rank.put(aFather, quotient * rank.get(b) / rank.get(a));

It's not hard to follow what happens. 不难理解会发生什么。 Pretty clever in fact! 其实很聪明!

Let's take a more complex example: 让我们举一个更复杂的例子:

a / b = 2.0, b / c = 3.0, c / d = 4.0, d / e = 5.0

During the first step ( MakeSet triggered by UnionFind uf = new UnionFind(set) ) each element is set to be its own parent, and all ranks are set to 1.0: 在第一步骤(MakeSet触发由UnionFind uf = new UnionFind(set) )的每个元素设定为它自己的父,并且所有等级被设置为1.0:

parent(a) = a, rank(a) = 1.0
...
parent(e) = e, rank(e) = 1.0

During the Union step, the rank of the node is set to the given quotient, while the rank of the parent stays the same (line 99). 联盟步骤中,节点的等级被设置为给定商数,而父的等级保持不变(线99)。 So after union(a, b, 2.0) parent(a) = b, rank(a) = 2.0 and the invariant is maintained for any node n: rank(n)/rank(parent(n)) = value , where value is from the equation being processed (the quotient argument). 因此,在union(a, b, 2.0) parent(a) = b, rank(a) = 2.0并为任何节点n保持不变: rank(n)/rank(parent(n)) = value ,其中value来自正在处理的方程式( quotient参数)。 At the end we get: 最后,我们得到:

parent(a) = b, rank(a) = 2.0
parent(b) = c, rank(b) = 3.0
parent(c) = d, rank(c) = 4.0
parent(d) = e, rank(d) = 5.0
parent(e) = e, rank(e) = 1.0

During the Compress step, if the parent of the node being searched is not the representative node of the set, then it is set to be by recursively searching for the parent of the parent of the parent... and setting the rank of the current node as the current rank multiplied by the rank of the parent (line 87). 在“ 压缩”步骤中,如果要搜索的节点的父级不是集合的代表节点 ,则通过递归搜索该父级的父级的父级并设置当前节点的等级来将其设置为节点作为当前等级乘以父级的等级(第87行)。 So in the end we arrive at: 所以最后我们得出:

parent(a) = e, rank(a) = 120.0
parent(b) = e, rank(b) = 60.0
parent(c) = e, rank(c) = 20.0
parent(d) = e, rank(d) = 5.0
parent(e) = e, rank(e) = 1.0

So indeed rank(a) = rank(b) * 2.0, rank(b) = rank(c) * 3.0 etc. just as given in the input equations. 因此,实际上,正如输入方程式中给出的那样,等级(a)=等级(b)* 2.0,等级(b)=等级(c)* 3.0等。

Note that the representative node of a set (ie the ultimate parent, e in this example) always ends-up having a rank of 1.0. 请注意,集合的代表节点 (即最终父节点,在此示例中为e )始终以1.0排名结束。 This is why repeatedly calling compressedFind and executing line 87 doesn't further change the rank of a node, once it's been computed and the parent been set. 这就是为什么一旦计算出节点并设置了父节点后,重复调用compressedFind并执行第87行就不会进一步更改节点的等级的原因。

Now it's easy to see how line 59 works: if the query is a / b then rank(a) / rank(b) = 120.0 / 60.0 = 2.0 现在很容易看到第59行的工作方式:如果查询是a / b,则rank(a)/ rank(b)= 120.0 / 60.0 = 2.0

Terminology used from here: https://en.wikipedia.org/wiki/Disjoint-set_data_structure 从这里使用的术语: https : //en.wikipedia.org/wiki/Disjoint-set_data_structure

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM