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 }