###### tags: `Leetcode` `medium` `graph` `bfs` `python` `c++`
# 399. Evaluate Division
## [題目連結:] https://leetcode.com/problems/evaluate-division/
## 題目:
You are given an array of variable pairs ```equations``` and an array of real numbers ```values```, where ```equations[i] = [Ai, Bi]``` and ```values[i]``` represent the equation ```Ai / Bi = values[i]```. Each ```Ai``` or ```Bi``` is a string that represents a single variable.
You are also given some ```queries```, where ```queries[j] = [Cj, Dj]``` represents the ```jth``` query where you must find the answer for ```Cj / Dj = ?```.
Return the answers to all queries. If a single answer cannot be determined, return ```-1.0```.
**Note:** The input is always valid. You may assume that evaluating the queries will not result in division by zero and that there is no contradiction.
**Example 1:**
```
Input: equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
Output: [6.00000,0.50000,-1.00000,1.00000,-1.00000]
Explanation:
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 ]
```
**Example 2:**
```
Input: equations = [["a","b"],["b","c"],["bc","cd"]], values = [1.5,2.5,5.0], queries = [["a","c"],["c","b"],["bc","cd"],["cd","bc"]]
Output: [3.75000,0.40000,5.00000,0.20000]
```
**Example 3:**
```
Input: equations = [["a","b"]], values = [0.5], queries = [["a","b"],["b","a"],["a","c"],["x","y"]]
Output: [0.50000,2.00000,-1.00000,-1.00000]
```
## 解題想法:
* 此題為:
* equations=[['a','b']], values=[0.5]
* 表示**a/b**=0.5
* queries=['b','a'],表示欲求**b/a**??
* 若queries中出現equations未出現的字母則return -1
* 使用圖解:
* **Step1**: 建立有向邊
* equations=[['x','y']],values=[v]
* case1: **x/y=v** 圖為**x->[y,v]**
* case2: **y/x=1/v** 圖為**y->[x,1/v]**
``` python=
edge=defaultdict(list)
#建立有向邊
for i in range(len(equations)):
x,y = equations[i]
v = values[i]
edge[x].append([y,v]) #x->y 即 x/y=v
edge[y].append([x,1.0/v]) #y->x 即 y/x =1/v
```
* **Step2**: 計算互相有關係點為連通分量
* init:
* clusters=[] :存連通分量集合
* visit=set() :查看是否已經拜訪過此點
* **找個特定點,求其他點與他的關係**
``` python=
for x,y in equations:
map={} #存當前數到某特定點的關係
if x not in visit:
start=x #若該點沒遍歷過 就已他為特定點
visit.add(start) #set用add remove
map[start]=1 #自己除自己為1
#用bfs遍歷 該點為首到其他點的相除值
head=[start]
while head:
cur=head.pop()
for node,val in edge[cur]: #找其鄰居
if node not in visit:
visit.add(node)
head.append(node)
#計算start與該點的相除關係: start/該點
map[node]=map[cur]*val
clusters.append(map)
'''
ex: equations = [["a","b"],["b","c"]]
values = [2.0,3.0]
2 3
a---->b---->c
1/2 1/3
clusters=[{'a': 1, 'b': 2.0, 'c': 6.0}, {}]
為a的視角除其他人: {'a': 1, 'b': 2.0, 'c': 6.0}
'''
```
* **Step3**: 求queries的組合
* 其中: **res.append(case[y]/case[x])**
* 要相反!!!!
* ex: 求["a","c"], x='a',y='c'
* case中: {'a': 1, 'b': 2.0, 'c': 6.0}
* case中的'a'、'c'為,a/a=1, a/c=6
* 所以求a/c為 case['c']/case['a']= 6/1=6
```python=
res=[]
for x,y in queries:
haveRes=False
for case in clusters:
if x in case and y in case:
res.append(case[y]/case[x])
haveRes=True
break
if not haveRes:
res.append(-1)
```
## Python:
``` python=
from collections import defaultdict
class Solution(object):
def calcEquation(self, equations, values, queries):
"""
:type equations: List[List[str]]
:type values: List[float]
:type queries: List[List[str]]
:rtype: List[float]
"""
edge=defaultdict(list)
#建立有向邊
for i in range(len(equations)):
x,y = equations[i]
v = values[i]
edge[x].append([y,v]) #x->y 即 x/y=v
edge[y].append([x,1.0/v]) #y->x 即 y/x =1/v
clusters=[] #存連通分量集合
#visit查看是否已拜訪過此點
visit = set() #用set 主要為集合不會包含重複值
#計算互相有關係點為連通分量
#找個特定點 求其他點與他的關係
for x,y in equations:
map={} #存當前數到某特定點的關係
if x not in visit:
start=x #若該點沒遍歷過 就已他為特定點
visit.add(start) #set用add remove
map[start]=1 #自己除自己為1
#用bfs遍歷 該點為首到其他點的相除值
head=[start]
while head:
cur=head.pop()
for node,val in edge[cur]: #找其鄰居
if node not in visit:
visit.add(node)
head.append(node)
#計算start與該點的相除關係: start/該點
map[node]=map[cur]*val
clusters.append(map)
#print(clusters)
#[{'a': 1, 'b': 2.0, 'c': 6.0}, {}]
#print('為a的視角除其他人:',clusters[0])
#為a的視角除其他人: {'a': 1, 'b': 2.0, 'c': 6.0}
res=[]
for x,y in queries:
haveRes=False
for case in clusters:
if x in case and y in case:
#要相反!!!! ex: case存的 'b':2.0 是指 a/b = 2.0
#所以求b/a 要用case[b]/case[a]
#ex: 求["a","c"], x='a',y='c'
#case中: {'a': 1, 'b': 2.0, 'c': 6.0}
#case中的'a'、'c'為,a/a=1, a/c=6
#所以求a/c為 case['c']/case['a']= 6/1=6
res.append(case[y]/case[x])
haveRes=True
break
if not haveRes:
res.append(-1)
return res
equations = [["a","b"],["b","c"]]
values = [2.0,3.0]
queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
result = Solution()
ans=result.calcEquation(equations,values,queries)
print(ans)
```
## C++:
* 寫的超亂請見諒
``` cpp=
class Solution {
public:
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
unordered_map<string, vector<pair<string, double>>> graph;
//connect the graph
for (int i=0; i<equations.size(); i++){
string x=equations[i][0], y=equations[i][1];
double v=values[i];
graph[x].push_back(pair(y,v));
graph[y].push_back(pair(x,double(1/v)));
}
vector<unordered_map<string, double>> clusters;
unordered_set<string> visited;
//find the clusters in the graph
for (int i=0; i<equations.size(); i++){
unordered_map<string, double> map;
string x=equations[i][0], y=equations[i][1];
if (visited.find(x)==visited.end()){
visited.insert(x);
map[x]=1; // x/x=1
queue<string> que;
que.push(x);
while (!que.empty()){
string cur=que.front(); que.pop();
for (auto &neighber: graph[cur]){
if (visited.find(neighber.first)==visited.end()){
visited.insert(neighber.first);
que.push(neighber.first);
map[neighber.first]=map[cur]*neighber.second;
}
}
}
clusters.push_back(map);
}
}
//get the res
vector<double> res;
for (int i=0; i<queries.size(); i++){
string x=queries[i][0], y=queries[i][1];
bool haveRes=false;
for (auto& clusterMap: clusters){
if ((clusterMap.find(x)!=clusterMap.end()) && (clusterMap.find(y)!=clusterMap.end())){
res.push_back(clusterMap[y]/clusterMap[x]);
haveRes=true;
break;
}
}
if (!haveRes)
res.push_back(-1);
}
return res;
}
};
```