图的最短路径-Bellman-Ford算法
Dijkstra算法无法解决带有负权边的图,为此要用到Bellman-Ford算法(贝尔曼-福特算法)
算法思路如下:
- 在第一次遍历前,先假定从起点到各点的距离都为正无穷
- 枚举每一条边,若发现该边可以使起点到某一点的路径变短,则更新距离
- 由于在n个顶点的图中,最短路径最多有n-1条边,所以将第2步循环n-1次。
总结:
因为最短路径最多有n-1条边,因此Bellman-Ford算法最多有n-1个阶段。每个阶段中,我们对每一条边进行松弛操作,在进行完n-1个阶段后,我们得出最多经过n-1条边的最短路径。
该算法可以判定带有负权环的图,
可见有的顶点的最短路径在中途就已经确定,但每次还需要判断,因此这里有优化空间(添加布尔值判断和基于队列优化)
示例代码:
整体代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #include<iostream> using namespace std; #define inf 999999;
int city, road;
void bellmanFord(int* u,int* v,int* w,int start) { int* dis = new int[city + 1]; for (int i = 1; i <= city; i++) dis[i] = inf; dis[start] = 0;
for (int i = 0; i < city - 1; i++) { bool check = false; for (int j = 0; j < road; j++) { if (dis[v[j]] > dis[u[j]] + w[j]) { dis[v[j]] = dis[u[j]] + w[j]; check = true; } } if (check == false) { break; } }
for (int i = 1; i <= city; i++) { cout << dis[i] << " "; }
delete[] dis; }
int main() { cin >> city >> road; int* u = new int[road]; int* v = new int[road]; int* w = new int[road]; for (int i = 0; i < road; i++) { cin >> u[i] >> v[i] >> w[i]; }
bellmanFord(u, v, w, 1); return 0; }
|
核心代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| void bellmanFord(int* u,int* v,int* w,int start) { int* dis = new int[city + 1]; for (int i = 1; i <= city; i++) dis[i] = inf; dis[start] = 0;
for (int i = 0; i < city - 1; i++) { bool check = false; for (int j = 0; j < road; j++) { if (dis[v[j]] > dis[u[j]] + w[j]) { dis[v[j]] = dis[u[j]] + w[j]; check = true; } } if (check == false) { break; } }
for (int i = 1; i <= city; i++) { cout << dis[i] << " "; }
delete[] dis; }
|
- 在每个阶段对每一条边进行松弛操作
- 进行n-1轮松弛后,若仍有边满足松弛条件,则图中有负权环
基于队列优化代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| bool* book = new bool[city + 1]; for (int i = 1; i <= city; i++) book[i] = false;
int queue[2502]; int head = 0; int tail = 0;
queue[tail++] = start; book[start] = true;
while (head != tail) { for (int i = 0; i < road; i++) { if (u[i] == queue[head]) { if (dis[v[i]] > dis[u[i]] + w[i]) { dis[v[i]] = dis[u[i]] + w[i]; if (book[v[i]] == false) { queue[tail++] = v[i]; book[v[i]] = true; } } } }
book[head] = false; head++; }
|