单源最短路径
从源点到终点的路径可能存在三种情况:1. 没有路径 2. 只有一条路径 3. 有多条路径
迪杰斯特拉(Dijkstra)
思路:按照路径长度递增的次序从源点到终点的路径。
- 假设 G r a p h [ ] [ ] Graph[][] Graph[][]为有向网的邻接矩阵, S S S为已找到最短路径结点的集合,其初始状态为只含一个顶点,即源点。另设一个一维数组 D i s t [ n ] Dist[n] Dist[n],其中每个分量表示当前所找到的从源点出发(经过集合S中的顶点)到各个终点的最短路径长度。显然, D i s t Dist Dist的初值为:
D i s t [ k ] = G r a p h [ i ] [ k ] Dist[k] = Graph[i][k] Dist[k]=Graph[i][k]1
- 选择 u u u,使得
D i s t [ u ] = m i n { D i s t [ w ] ∣ w ∉ S , w ∈ V ( G ) } Dist[u] = min\{Dist[w] | w ∉ S, w∈ V(G)\} Dist[u]=min{Dist[w]∣w∈/S,w∈V(G)}
u u u为目前找到的从源点出发的最短路径的结点。将这些结点 u u u并入集合 S S S。- 修改 D i s t Dist Dist数组中所有尚未找到最终路径的结点的对应分量值。如果 G r a p h [ u ] [ w ] Graph[u][w] Graph[u][w]为有限值,即从顶点 u u u到顶点 w w w有弧存在,并且
D i s t [ u ] + G r a p h [ u ] [ w ] < D i s t [ w ] Dist[u]+Graph[u][w] < Dist[w] Dist[u]+Graph[u][w]<Dist[w]
则令:
D i s t [ w ] = D i s t [ u ] + G r a p h [ u ] [ w ] Dist[w] = Dist[u] + Graph[u][w] Dist[w]=Dist[u]+Graph[u][w]- 重复上述(2)和(3)的操作n-1次,即可求得从源点到所有终点的最短路径。
思路:copy自这个博客
#include<iostream>
#include<vector>
using namespace std;
void Dijkstra(int n, int s, const vector<vector<int> > &G, vector<int> &prev) {
// initilization
vector<int> dist(n, INT_MAX);
vector<bool> S(n, false); // 判断是否在S集合中
for (int i = 0; i < n; i++) {
dist[i] = G[s][i];
if (dist[i] == INT_MAX) {
prev[i] = 0;
}
else {
prev[i] = s; // 有值的结点前驱结点一定是源点
}
}
S[s] = true;
dist[s] = 0;
// find next path for the shortest path
int u; // next
int value = INT_MAX;
for (int i = 0; i < n; i++) {
if (!S[i] && dist[i] < value) {
value = dist[i];
u = i;
}
}
// update
for (int i = 0; i < n; i++) {
if (!S[i] && dist[i] != INT_MAX) {
int temp = dist[u] + G[u][i];
if (temp < dist[i]) {
dist[i] = temp;
prev[i] = u;
}
}
}
}
void searchPath(const vector<int>& prev, int s, int e) {
vector<int> rpath;
rpath.push_back(e);
int temp = prev[e];
while (temp != s) {
rpath.push_back(temp);
temp = prev[temp];
}
rpath.push_back(s);
for (auto it = rpath.rbegin(); it != rpath.rend();it++) {
if (it != rpath.rend())
cout << *it << "->";
else
cout << *it << endl;
}
}
int main() {
int n, edge;
vector<int> prev;
vector<vector<int>> G(n, vector<int>(n,INT_MAX)) ;
int st, en, weight;
// input
cin >> n >> edge;
// Graph
for (int i = 0; i < edge; i++) {
cin >> st >> en >> weight;
G[st][en] = weight;
G[en][st] = weight;
}
Dijkstra(n, st, G, prev);
int T;
cin >> T;
while (T--) {
int v;
cin >> v;
searchPath(prev, st, en);
}
}
佛洛依德(略)
i i i为源点在途中的序号 ↩︎