最短路演算法Floyed, Dijkstra, Bellman-Ford, SPFA
阿新 • • 發佈:2018-11-25
Floyed演算法,複雜度o(n^3);
更新i->j的距離,通過中介點k,如果能夠通過k使得i->j的距離更短,那麼更新。
程式碼
void Folyed() { for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i != j && i != k && j != k && d[i][j] > d[i][k] + d[k][j]) { d[i][j] = d[i][k] + d[k][j]; } } } } }
Dijkstra演算法,普通複雜度O(n^2),堆優化O(nlgn)
有個集合s,和原始圖G,一個最短距離陣列d。從起點開始,每次新增一個u,如果能夠從中介點u更新到u所有的鄰接點v的最短距離,那麼當前可以更新的是起點到v的最短距離d[v]。直到s中包括所有點,演算法結束,最後d陣列就是起點到其他所有點的最短距離。
堆優化的話,就避免很多重複邊的判斷。
void Dijkstra(int st, int ed) { memset(d, INF, sizeof(d)); memset(vis, false, sizeof(vis)); d[st] = 0; for (int i = 0; i < n; i++) { int u = -1, MIN = INF; for (int j = 0; j < n; j++) { if (vis[j] == false && d[j] < MIN) { MIN = d[j]; u = j; } } if (u == -1) return; vis[u] = true; for (int v = 0; v < n; v++) { if (vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]) { d[v] = d[u] + G[u][v]; } } } }
堆優化。
struct edge { int v; int d;//距離 edge(){} edge(int _v, int _d) { v = _v; d = _d; } }; vector<edge> E[maxn]; void Clear() { for (int i = 0; i < maxn; i++) { E[i].clear(); } memset(pre, 0, sizeof(pre)); } struct node { int v; int d; bool operator<(const node &a)const{ return d > a.d; } }; void Dijkstra(int st, int ed) { memset(d, INF, sizeof(d)); memset(minCost, INF, sizeof(minCost)); memset(vis, false, sizeof(vis)); d[st] = 0; minCost[st] = 0; priority_queue<node> q; q.push(node{st, 0}); while (!q.empty()) { node f = q.top(); q.pop(); int u = f.v; if (vis[u] == true) continue; vis[u] = true; for (int i = 0; i < E[u].size(); i++) { int v = E[u][i].v; if (vis[v] == true) continue; if (d[v] > d[u] + E[u][i].d) { d[v] = d[u] + E[u][i].d; pre[v] = u; q.push(node{v, d[v]}); } } } }
Bellman-Ford,複雜度O(n*E),頂點數n,邊數E
void bellman-ford() {
for (int i = 0; i < n - 1; i++) {//最多n-1次
for (int u = 0; u < n; u++) {
for (int j = 0; j < Adj[u].size(); j++) {
int v = Adj[u][j].v;
int dis = Adj[u][j].dis;
if (d[u] + dis < d[v]) {
d[v] = d[u] + dis;
}
}
}
}
}
SPFA,複雜度O(k*E),k平均值一般等於2
spfa演算法就是對bellman-ford的一種佇列優化,避免了很多無意義的判斷和操作。
bool SPFA(int s) {
memset(inq, false, sizeof(inq));
memset(num, 0, sizeof(num));
memset(d, INF, sizeof(d));
prority_queue<int> q;
q.push(s);
inq[s] = true;
num[s]++;
d[s] = 0;
while (!q.empty()) {
int u = q.top(); q.pop();
inq[u] = false;
//
for (int j = 0; j < Adj[u].size(); j++) {
int v = Adj[u][j].v;
int dis = Adj[u][j].dis;
if (d[u] + dis < d[v]) {
d[v] = d[u] + dis;
if (!inq[v]) {
inq[v] = true;
q.push(v);
num[v]++;
if (num[v] > n-1) return false;
}
}
}
}
return true;
}