最短路演算法
阿新 • • 發佈:2020-09-11
Floyd
純暴力,三個 for
迴圈
複雜度: \(O(V^3)\)
for(int k = 1;k <= n;k++){
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
if(dis[i][k] + dis[k][j] < dis[i][j]){
//...
}
}
}
}
Bellman-Ford
用邊去進行鬆弛操作,可以判環
複雜度: \(O(VE)\)
#include<bits/stdc++.h> using namespace std; const int maxm = 2e5 + 10; const int maxn = 1e5 + 10; struct E { int from, to, w; }Edges[maxm]; int dis[maxn]; int n, m, s; bool bellman_ford(int s) { for (int i = 1; i < n; i++) {//鬆弛n-1次 for (int j = 0; j < m; j++) { int f = Edges[j].from, t = Edges[j].to, w = Edges[j].w; if (dis[t] > dis[f] + w) { dis[t] = dis[f] + w; } } } for (int j = 0; j < m; j++) { int f = Edges[j].from, t = Edges[j].to, w = Edges[j].w; if (dis[t] > dis[f] + w) { return false;//負環 } } return true; } int main() { scanf("%d %d %d", &n, &m, &s); memset(dis, 0x3f, sizeof dis); dis[s] = 0;//注意dis的初始化 for (int i = 0; i < m; i++) { scanf("%d%d%d", &Edges[i].from, &Edges[i].to, &Edges[i].w); if (Edges[i].from == s) { dis[Edges[i].to] = Edges[i].w;//初始化 } } bellman_ford(s); for (int i = 1; i <= n; i++) { printf("%d%s", dis[i], i == n ? "\n" : " "); //printf("%d%c",dis[i]," \n"[i==n]); } }
Dijkstra
複雜度 : \(O(VlogV+E)\)
struct Node { long long d; int u; bool operator < (const Node& rhs)const { //rhs,right-hand-side return d > rhs.d; } }; void dijkstra(int s) { priority_queue<Node>Q; for (int i = 1;i <= n;i++) { d[i] = INF; } d[s] = 0; memset(vis, 0, sizeof(vis)); Q.push(Node{ 0,s }); while (!Q.empty()) { Node x = Q.top();Q.pop(); int u = x.u; if (vis[u]) { continue; } vis[u] = 1; for (int i = 0;i < G[u].size();i++) { Edge e = edges[G[u][i]]; if (d[e.to] > d[u] + e.dist) { d[e.to] = d[u] + e.dist; p[e.to] = G[u][i]; Q.push(Node{ d[e.to],e.to }); } } } }
SPFA
\(O(kE)\) ,\(k\) 為每個節點入隊次數
最壞 \(O(EV)\)
#include<bits/stdc++.h> using namespace std; const int maxn = 1e6 + 10; struct Edge { int to, w, next; }E[maxn]; int head[maxn], tot; void AddEdge(int from, int to, int w) { E[tot] = Edge{ to,w,head[from] }; head[from] = tot++; } int n, m, s; const int inf = 0x3f3f3f3f;// inf > (1e9) int dis[maxn], vis[maxn]; void spfa() { queue<int> q; memset(dis, 0x3f, sizeof(int) * (n + 10)); memset(vis, 0, sizeof(int) * (n + 10)); q.push(s); dis[s] = 0; vis[s] = 1; //第一個頂點入隊,進行標記 while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for (int i = head[u]; ~i; i = E[i].next) { int v = E[i].to; if (dis[v] > dis[u] + E[i].w) { dis[v] = dis[u] + E[i].w; if (vis[v] == 0) { //此處判環 //if(++cnt[v] >= n) 有負環 vis[v] = 1; q.push(v); } } } } } int main() { scanf("%d%d%d", &n, &m, &s); memset(head, 0xff, sizeof(int) * (n + 10)); tot = 0; for (int i = 0; i < m; i++) { int a, b, w; scanf("%d%d%d", &a, &b, &w); AddEdge(a, b, w); } spfa(); for (int i = 1; i <= n; i++) { printf("%d%c", dis[i] == 0x3f3f3f3f ? (1 << 31) - 1 : dis[i], " \n"[i == n]); } }