图二:
因为from不管通过哪条路径相对于根节点t的权值都是不会变的所以可以得出
w[from] * w[f] == val * w[to]
`
`
方法 —— 带权并查集:
因为元素与元素之间存在除法关系,所以可以用并查集来处理元素之间的联系,但又因为使除法,所以元素自身带有权值,所以在使用并查集时,应将权值关系所考虑进去
- 使用map将字符串映射为数字
- 因为元素之间存在权值关系,所以我们在使用
fm切片进行表示各个元素的父节点是谁的时候,也要使用w切片来表示各个元素与根节点的权值关系 - 为
fm,w两个切片分配空间,其中他们的下标所表示的就是各个元素,其长度就是元素的种类即len(id) - 初始化两个切片,初始化后的结果就是各个元素的父节点是自己,即并查集的原始状态,各个元素没有联系,因为都指向自己,那么权值自然都是默认的1
find函数返回当前节点的根节点,如何判断是根节点即其父节点是自身- 如果当前节点不是根节点,则递归查找,直到找到其根节点
f,在递归的同时我们还要维护当前节点的权值,因为我们w切片中保存的只是当前节点相对于父节点的权值,我们需要的是当前节点相对于根节点的权值 - 如何更新
w,自然是在我们递归find的时候,当我们递归到最深处往回返的时候,w[index] *= w[fm[index]]使路径上的所有w节点得到更新,使它们都更新为相对于根节点的权值,因为是往回返的时候更新,所以代码自然写在f := find(fm[index])递归代码的后面 merge函数则是通过除法关系来更新fm,w两个并查集切片工具- 更新自然是使
from的根节点的父节点变为to的根节点,从而更新fm - 以及通过除法的结果来更新
from根节点的相对于to根节点的权值,计算方法我们可以通过图二得出w[f] = val * w[to] / w[from],从而更新w - 然后我们只需要通过遍历
equations得到各个元素之间的除法关系,然后传入merge中,对fm,w两个切片进行初步更新,也许它还没有到达最终我们想要的结果,但这无关紧要,因为我们在每次使用find函数时,都会为我们更新这两个切片 - 最后我们生成我们的答案切片
ans,长度自然就是问题queries的长度 - 最后一个for循环,将我们的问题元素拿出来,首先判断问题元素是否在我们的
idmap中出现过,如果没有出现过那我们自然也无法求值,将相应的ans置为-1,如果两个元素的根节点不是同一个,那么说明这两个元素之间没有关系,我们自然也无法求值 - 如果以上情况都没有出现,那么我们只需要
ans[i] = w[a] / w[b],因为我们w中存放的正是相对于根节点的权值,可以之间相除 - 有没有可能
w中存放的不是相对于根节点权值,当然不可能,因为我们在相除之前就使用过find函数,我们的w会自动更新。
func calcEquation(equations [][]string, values []float64, queries [][]string) []float64 {
//给方程组中的每个变量编号
id := make(map[string]int)
for _,v := range equations {
a, b := v[0],v[1]
if _,has := id[a]; !has {
id[a] = len(id)
}
if _,has := id[b]; !has {
id[b] = len(id)
}
}
fm := make([]int,len(id))
w := make([]float64,len(id))
for i := range fm {
fm[i] = i
w[i] = 1
}
var find func (int) int
find = func (index int) int {
if fm[index] != index {
f := find(fm[index])
w[index] *= w[fm[index]]
fm[index] = f
}
return fm[index]
}
merge := func (from, to int, val float64) {
f,t := find(from),find(to)
fm[f] = t
w[f] = val * w[to] / w[from]
}
for i,v := range equations {
merge(id[v[0]],id[v[1]],values[i])
}
ans := make([]float64, len(queries))
for i,v := range queries {
a, has1 := id[v[0]]
b, has2 := id[v[1]]
if has1 && has2 && find(a) == find(b) {
ans[i] = w[a] / w[b]
}else {
ans[i] = -1
}
}
return ans
}