Floyd-Warshall算法:
O
(
∣
V
∣
3
)
O(|V|^3)
O(∣V∣3) 内计算任意两点的最短路。(dp的思想)
计算点 i
到 j
的最短路,考虑最短路是否会经过点 k
。有两种情况:
- 经过点
k
:d[i][j] = d[i][k] + d[k][j]
- 不经过
k
:d[i][j]
则最短路的状态转移方程:d[i][j] = min(d[i][j], d[i][k] + d[k][j])
使用三个 for
循环,完成计算(从外到内分别处理 k、i、j
)
for(int k = 0; k < N; i++){
for(int i = 0; i < N; i++) {
for(int j = 0; j < N; j++) {
d[i][j] = min(d[i][j], d[i][k] + d[k][j])
}
}
}
在本题中,使用 Floyd 算法需要做一些小改进
dp[i][i]
初始化为1- 状态转移方程变为乘法
dp[i][j] = min(dp[i][j], dp[i][k]*dp[k][j])
- 不能到达的点始终维持
INT_MAX
,不能相乘
附上代码:
Floyd算法
class Solution {
public:
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
vector<double> out;
map<string, int> proj;
int cnt = 0;
for(auto x : equations){
if(proj.count(x[0]) == 0) proj[x[0]] = cnt++;
if(proj.count(x[1]) == 0) proj[x[1]] = cnt++;
}
vector<vector<double>> graph(cnt, vector<double>(cnt, INT_MAX));
for(int i = 0; i<cnt; i++) graph[i][i] = 1;
for(int i=0; i<equations.size(); i++){
int A = proj[equations[i][0]], B = proj[equations[i][1]];
graph[A][B] = values[i];
graph[B][A] = 1/values[i];
}
for(int k=0; k<cnt; k++){
for(int i=0; i<cnt; i++){
for(int j=0; j<cnt; j++){
if(graph[i][k] == INT_MAX || graph[k][j] == INT_MAX) continue;
graph[i][j] = min(graph[i][j], graph[i][k]*graph[k][j]);
}
}
}
for(auto x : queries){
if(proj.count(x[0]) == 0 || proj.count(x[1]) == 0) out.push_back(-1.0);
else {
int A = proj[x[0]], B = proj[x[1]];
if(graph[A][B] >= INT_MAX) out.push_back(-1.0);
else out.push_back(graph[A][B]);
}
}
return out;
}
};
存图(邻接表) + dfs(查询)
typedef pair<int,double> P;
class Solution {
public:
double dfs(vector<vector<P>>& g, int curr, int dest, set<int>& select){
if(curr == dest) return 1.0;
for(auto x : g[curr]){
if(select.count(x.first) != 0) continue;
select.insert(x.first);
double cnt = dfs(g, x.first, dest, select);
if(cnt > 0) return x.second*cnt;
select.erase(select.find(x.first));
}
return -1;
}
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
vector<double> out;
map<string, int> proj;
int cnt = 0;
for(auto x : equations) {
if(proj.count(x[0]) == 0) proj[x[0]] = cnt++;
if(proj.count(x[1]) == 0) proj[x[1]] = cnt++;
}
// 构建图,存储每一条加权有向边
vector<vector<P>> graph(proj.size(), vector<P>());
for(int i=0; i<equations.size(); i++){
int A = proj[equations[i][0]], B = proj[equations[i][1]];
graph[A].push_back(P(B, values[i]));
graph[B].push_back(P(A, 1.0/values[i]));
}
// 对每个查询query,dfs 查找路径对应的权值乘积
for(auto x : queries){
if(proj.count(x[0]) == 0 || proj.count(x[1]) == 0) {out.push_back(-1.0); continue;}
int A = proj[x[0]], B = proj[x[1]];
set<int> ss;
ss.insert(A);
out.push_back(dfs(graph, A, B, ss));
}
return out;
}
};