---
###### tags: `2020 師大附中校隊培訓`
---
# 最短路徑
## 2020 師大附中校隊培訓
#### joylintp
#### 10.28.2020
---
## 最短路徑
最短路徑即為兩點間所有路徑中邊權和最小者
最短路徑上不允許存在負環,否則可以經由不斷通過負環讓路徑權重和持續變小
----
### 單點源最短路徑
求出一個點到所有點的最短路徑
### 多點源最短路徑
求出所有點對的最短路徑
----
### 鬆弛
### Relaxation
對於兩個點 $u$、$v$,設其之間的邊權為 $w_{u,v}$
若起點到它們的距離 $d_u$、$d_v$ 滿足$d_u+w_{u, v}<d_v$,
即可把 $d_v$ 更新成 $d_u+w_{u, v}$,使 $u$ 到 $v$ 的距離變短,
這個動作就叫鬆弛
---
## Bellman-Ford algorithm
* 單點源最短路徑
* 可以有負邊,可判斷負環
----
### Bellman-Ford algorithm
* 將起點最短路徑長設為 0,其餘長度為無限大
* 枚舉每條邊,嘗試每條邊是否可進行鬆弛
若第 $V$ 次枚舉時仍有邊可以鬆弛,即表示圖中有負環;
否則,表示所有點已為最短路徑
時間複雜度 $O(VE)$
---
## Dijkstra algorithm
* 單點源最短路徑
* 不可有負邊,不可判斷負環
----
### Dijkstra algorithm
* 將起點最短路徑長設為 0,其餘長度為無限大
* 在所有已找到最短路徑的點中,尋找所有往外的邊中權重最小者延伸
最糟情況下每條邊都需被鬆弛一次
時間複雜度 $O(E\ log\ E)$
----
```cpp=
cin >> n >> m >> s;
for (int i = 1; i <= n; i++)
dis[i] = 1e18;
dis[s] = 0;
int a, b, c;
while (m--)
cin >> a >> b >> c, edge[a].push_back({b, c});
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push({0, s});
while (!pq.empty())
{
int u = pq.top().second, d = pq.top().first;
pq.pop();
if (vis[u])
continue;
vis[u] = true;
for (auto p : edge[u])
if (!vis[p.first] && d + p.second < dis[p.first])
dis[p.first] = d + p.second, pq.push({dis[p.first], p.first});
}
for (int i = 1; i <= n; i++)
cout << dis[i] << " \n"[i == n];
```
---
## Floyd-Warshall algorithm
* 多點源最短路徑
* 可以有負邊,可判斷負環
----
### Floyd-Warshall algorithm
### 動態規劃
* 令 $dp_{i,j}$ 為 $i$ 到 $j$ 的最短路徑長,
* 將 $dp_{i, j}$ 設為 $w_{i,j}$,$dp_{i, i}$ 設為 0
* $dp_{i, j} = min(dp_{i,k}+dp_{k, j}, dp_{i, j})$
時間複雜度 $O(V^3)$
----
```cpp=
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
dis[i][j] = 2e18;
for (int i = 1; i <= n; i++)
dis[i][i] = 0;
int u, v, w;
while (m--)
cin >> u >> v >> w, dis[u][v] = min(dis[u][v], w);
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
for (int i = 1; i <= n; i++)
if (dis[i][i] < 0)
cout << "-1\n";
for (int i = 1; i <= n; i++, cout << '\n')
for (int j = 1; j <= n; j++)
cout << dis[i][j] << ' ';
```
---
{"metaMigratedAt":"2023-06-15T14:51:14.521Z","metaMigratedFrom":"Content","title":"最短路徑","breaks":true,"contributors":"[{\"id\":\"6b95215f-91a7-4eaf-bcfe-d43740108f96\",\"add\":2320,\"del\":42}]"}