Bellman-Ford演算法和佇列優化(SPFA)——求單源最短路徑
阿新 • • 發佈:2019-01-11
來源自我的部落格
#include <stdio.h>
#include <limits.h>
int main(){
int n, m;
scanf("%d%d", &n, &m);
int u[10], v[10], w[10]; // 分別表示邊的兩頂點編號和權值
for (int i = 1; i <= m; i++){
scanf("%d%d%d", &u[i], &v[i], &w[i]);
}
int dis[10]; // 源點到任意點的距離
for (int i = 1; i <= n; i++){
dis[i] = INT_MAX;
}
dis[1] = 0;
int bak[i];
// 核心語句,迴圈n-1次
for (int k = 1; k <= n - 1; k++){
// 備份距離陣列以檢測是否已完成
for (int i = 1; i <= n; i++) bak[i] = dis[i];
// 每次迴圈遍歷所有邊
for (int i = 1; i <= m; i++){
// 判斷源點到點v[i]距離能不能通過走源點->點u[i]->點v[i]的路線更短
if (dis[v[i]] > dis[u[i]] + w[i]){
dis[v[i]] = dis[u[i]] + w[i];
}
}
// 迴圈完檢測當前dis是否有更新
bool check = 0;
for (int i = 1; i <= n; i++) {
if (bak[i] != dis[i]) {
check = 1;
break;
}
}
if (check = 0) break; // 如果 dis陣列沒更新,提前退出迴圈
}
// 檢測負權迴路
bool flag = 0;
for (int i = 1; i <= m; i++){
if (dis[v[i]] > dis[u[i]] + w[i]) flag = 1;
}
if (flag == 1) printf("有負權迴路\n");
// 輸出最終結果
for (int i = 1; i <= n; i++){
printf("%d ", dis[i]);
}
return 0;
}
// 佇列優化的Bellman-Ford演算法(SPFA演算法)
#include <iostream>
#include <climits>
#include <queue>
#include <vector>
using namespace std;
int main(){
int n, m;
cin >> n >> m;
vector <int> dis(n, INT_MAX); // 源點到每個點的距離
dis[0] = 0;
vector <int> first(n, -1); // 每個結點相鄰的邊中第一條邊的編號,-1表示沒有相鄰的邊
vector <int> next(m, -1); // 每條邊的下一條邊的編號
vector <bool> book(n, false); // true表示在佇列中
vector <int> u(m), v(m), w(m); // 每條邊的兩頂點和權值
// 建立鄰接表
for (int i = 0; i < m; i++){
cin >> u[i] >> v[i] >> w[i];
// 將新邊頭插到鄰接表中
next[i] = first[u[i]]; // 此邊的下一邊為u[i]起頭的第一條邊
first[u[i]] = i; // 將此邊作為u[i]起頭的第一條邊
}
queue <int> Q;
// 將源點入佇列
Q.push(0);
book[0] = true;
// 佇列不空時迴圈
while (!Q.empty()){
// 取隊首
int k = first[Q.front()]; // k表示隊首點的第一條鄰接邊的編號
// 掃描隊首頂點所有的鄰邊
while (k != -1){
// 判斷源點到點v[k]的距離能不能通過源點->點u[k]->點v[k]來更新
if (dis[v[k]] > dis[u[k]] + w[k]){
dis[v[k]] = dis[u[k]] + w[k];
// 判斷點v[k]在不在佇列中
if (book[v[k]] == false){
// 不在佇列中則入隊
Q.push(v[k]);
book[v[k]] = true;
}
}
// k移向下一條鄰接邊
k = next[k];
}
// 隊首結點用完了,可以出隊了
book[Q.front()] = false;
Q.pop();
}
// 輸出源點到其餘各個頂點的最短路徑
for (int i = 0; i < n; i++){
cout << dis[i] << " ";
}
cout << endl;
return 0;
}