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). Given some queries, return the answers. If the answer does not exist, return -1.0.Example:
Given a / b = 2.0, b / c = 3.0.
queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? .
return [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
, whereequations.size() == values.size()
, and the values are positive. This represents the equations. Returnvector<double>
.appAccording to the example above:ui
equations = [ ["a", "b"], ["b", "c"] ], values = [2.0, 3.0], queries = [ ["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.
这道题抽象以后能够理解为,给定一系列图中的边,边的值表示其两端节点的比例,如今给定一系列图中节点对,求每对节点的比例。那不管如何,首先咱们要先根据给定的equations和values把图先建出来。因为是无向图,不分先后,因此咱们不只要记下a到b的边,也要记下b到a的边,即倒数。图建好之后,若是给定的query并非不少,那么最简单的就是从节点a开始,深度搜索寻找节点b,并同时记录下路径上的比例并乘起来,一旦找到节点b就返回这个乘积。这里代码使用了递归来实现DFS。this
func compute(graph map[string]map[string]float64, first, second string, visited map[string]bool, value float64) float64 { nexts := graph[second] for next, ratio := range nexts { if _, ok := visited[next]; !ok { // if the target is found, we return the final result if next == first { return value * ratio } else { // otherwise keep looking // set visited to true to avoid circle visited[next] = true res := compute(graph, first, next, visited, value * ratio) if res != -1 { return res } delete(visited, next) } } } return -1 } func buildGraph(equations [][]string, values []float64) map[string]map[string]float64 { graph := map[string]map[string]float64{} for i, equation := range equations { first := equation[0] second := equation[1] value := values[i] // initialize the map if not being created before if _, ok := graph[first]; !ok { graph[first] = map[string]float64{} } if _, ok := graph[second]; !ok { graph[second] = map[string]float64{} } // record both direction for this edge graph[first][second] = 1/value graph[second][first] = value } return graph } func calcEquation(equations [][]string, values []float64, queries [][]string) []float64 { graph := buildGraph(equations, values) res := []float64{} for _, query := range queries { first := query[0] second := query[1] value := -1.0 visited := map[string]bool{} // dfs and find the path from 'first' to 'second' value = compute(graph, first, second, visited, 1) res = append(res, value) } return res }
可是若是query不少,甚至要求图中每一个节点对两两之间的比例时,深度搜索就显得不是那么有效了。由于这时搜索会重复走不少次相同的路径。这种求两两之间最短路径有一个现成的算法:Floyd–Warshall 。基本上该算法就是经过三层循环,一层是中间节点,两层是开始和结束节点,穷举全部的可能性看是否开始和结束节点可否经过这个中间节点串联起来,若是能够的话就给图中加一条直接从开始节点到结束节点的边。这样虽然建图会花掉O(N^3)的时间,可是对每一个query就成了一个O(1)的操做。lua
使用该算法的时候要记得给每一个节点到自身也加一条值为1的边(本身对本身的比例是1),这样当中间节点和开始节点是一个节点时,不会把0乘进去code
func buildGraph(equations [][]string, values []float64) map[string]map[string]float64 { graph := map[string]map[string]float64{} for i, equation := range equations { first := equation[0] second := equation[1] value := values[i] if _, ok := graph[first]; !ok { graph[first] = map[string]float64{} } if _, ok := graph[second]; !ok { graph[second] = map[string]float64{} } graph[first][second] = 1/value graph[second][first] = value } return graph } func calcEquation2(equations [][]string, values []float64, queries [][]string) []float64 { graph := buildGraph(equations, values) for i := range graph { graph[i][i] = 1.0 for j := range graph { for k := range graph { ratio1, ok1 := graph[j][i] ratio2, ok2 := graph[i][k] if ok1 && ok2 { graph[j][k] = ratio2 * ratio1 } } } } res := []float64{} for _, query := range queries { first := query[0] second := query[1] value := -1.0 if _, ok := graph[second][first]; ok { value = graph[second][first] } res = append(res, value) } return res }