Dijkstra
- 从
1
-n
个点中选出一个当前最近的u
,(每次选出的u
不重复,即选过的不会再选) - 用这个
u
去更新与之相邻的v
,回到第一步 - 不断循环到没有节点可选或者找到了目标点。
int shortestPath(int node1, int node2) {
vector<long> d(n, INT_MAX); // 记录每个点的最短距离(以Node1开始)
vector<int> vis(n, 0); // 每个点是否访问过
d[node1] = 0;
int u = -1;
while (1) {
u = -1;
for (int i = 0; i < n; i++) { // 找到没有访问过的,最小的点u
if ((u < 0 || d[i] < d[u]) && !vis[i])
u = i;
}
if (u == -1)
break;
vis[u] = 1;
if(u==node2)return d[node2];
for (pii p : g[u]) {
int v = p.first, c = p.second;
d[v] = min(d[v], d[u] + c);
}
}
return d[node2] == INT_MAX ? -1 : d[node2];
}
堆优化最短路
vector<vector<pii>> g(n); // 稀疏图
for (auto& e : edges) {
int x = e[0], y = e[1], w = e[2];
g[x].push_back({y, w});
g[y].push_back({x, w});
}
vector<int> dis(n, -1);
dis[0] = 0;
priority_queue<pii, vector<pii>, greater<>> pq;
pq.emplace(0, 0);
while (!pq.empty()) {
auto [du, u] = pq.top(); // 当前最小距离点u
pq.pop();
if (dis[u] < du) // 已经有更小的dis[u]计算过了,这个之前的du就不要了
continue;
for (auto& [v, t] : g[u]) {
int nd = dis[u] + t;
if (dis[v] == -1 || nd < dis[v]) {
dis[v] = nd;
pq.emplace(dis[v], v);
}
}
}
return dis;
Floyd
可算出任意两点之间的距离
计算思路:假设现在计算从i
到j
,中间经过的最大的节点值为k
,表示为dfs(k,i,j)
;
对于k,我们可以选择:
- 不选之:
那么dfs(k,i,j)
=dfs(k-1,i,j)
; - 选之:
那么dfs(k,i,j)
=dfs(k-1,i,k)
+dfs(k-1,k,j)
;
因此dfs(k,i,j)
=min(dfs(k-1,i,j)
,dfs(k-1,i,k)
+dfs(k-1,k,j)
);
终止条件为dfs(-1,i,j)
,i
,j
之间没有节点可以走,返回w[i][j]
(直接距离,没有则为
∞
\infty
∞)
由于有很多重复计算,可以用三维数组进行记忆化;
vector<vector<int>> w(n, vector<int>(n, INT_MAX / 2));
for (vector e : edges) {
int x = e[0], y = e[1], c = e[2];
w[x][y] = w[y][x] = c;
}
vector<vector<vector<int>>> memo(
n, vector<vector<int>>(n, vector<int>(n, 0)));
function<int(int, int, int)> dfs = [&](int k, int i, int j) -> int {
if (k < 0)
return w[i][j];
int& r = memo[k][i][j];
if (r != 0)
return r;
r = min(dfs(k - 1, i, j), dfs(k - 1, i, k) + dfs(k - 1, k, j));
return r;
};
或者可以用动态规划
一定要把k
放在最外层
vector<vector<int>> w(n, vector<int>(n, INT_MAX / 2));
for (vector e : edges) {
int x = e[0], y = e[1], c = e[2];
w[x][y] = w[y][x] = c;
}
vector<vector<vector<int>>> f(
n + 1, vector<vector<int>>(n, vector<int>(n, 0)));
f[0] = w;
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
f[k + 1][i][j] = min(f[k][i][j], f[k][i][k] + f[k][k][j]);
}
}
}