Bellman-Ford Algorithm
Bellman-Ford Algorithm
08/07/2019
I. Mục đích
Tìm đường đi ngắn nhất từ 1 node (starting node) đến tất cả các nodes còn lại.
Ưu điểm: Có thể phát hiện mạch âm
II. Ý tưởng:
Gọi $distance[i]$ là đường đi ngắn nhất từ đỉnh $x$ (starting node) đến đỉnh i ($distance[x] = 0$)
- Sau lần
round 1
: những đỉnh $i$ kề $x$ sẽ xác định được $distance[i]$ (final value luôn đó)
… - Sau lần
round thứ k
: những shortest path từ $x$ đến $i$ nào mà kết quả có $k$ cạnh thì sẽ được xác định.
Mà shortest path từ $x$ đến $any\ i$ chỉ có thể có tối đa $n-1$ edges nên ta chỉ cần round
$n-1$ lần là tìm được tất cả các $distance[i]$
Về mặt hình dung ta có thể hiểu là:
Sau round 1
thì những đỉnh kề $i$ được discover, sau round 2
thì những đỉnh kề với những đỉnh đã discover lần trước
được discover, cứ vậy đến hết. Đây cũng là ý tưởng để cải tiến là ta chỉ cần duyệt các cạnh kề với các đỉnh vừa discover
mà không cần duyệt hết list cạnh
, tuy nhiên, cải tiến này không làm giảm độ phức Big-Oh.
Nhưng vì cài đặt là ta duyệt qua edges nên may mắn nào đó nó discover hết trong 1 lần duyệt là điều có thể xảy ra.
Nếu tất cả các $distance[i]$ đều có ít hơn $n-1$ edges thì các $distance[i]$ sẽ được xác định sớm hơn $n-1$ lần.
*round
: duyệt qua tất cả các cạnh của đồ thị được lưu trong edge list
.
III. Implement
Ta lưu đồ thị dưới dạng edge list
, mỗi phần tử là edge
với xuất phát từ $a$, đến $b$, và trọng số $w$.
1for(int i=1; i<=n; i++)
2 distance[i] = INF;
3distance[x] = 0;
4for(int i=1; i<=n-1; i++){
5 for(auto e:edges){
6 int a, b, w;
7 tie(a, b, w) = e;
8 distance[b] = min(distance[b], distance[a] + w);
9 }
10}
$$\Rightarrow O(n*m) $$
Hoàn toàn ta có thể thêm kĩ thuật truy vết để tìm ra các shortest path từ đỉnh $x$ đến $i$.
Kiểm tra mạch âm (Negative Cycle)
Nếu có mạch âm thì sau mỗi lần round
ta luôn có thể giảm $distance[i]$ (cứ đi qua cái cạnh âm đó) thì khái niệm shortest path không tồn tại.
Vì vậy, chỉ cần ta round
thêm 1 lần mà phát hiện bất kì $distance[i]$ nào giảm giá trị thì đồ thị chứa mạch âm.
1for(auto e:edges){
2 if (distance[a] + w < distance[b]) {
3 cout << "Graph contains negative cycle!" << endl;
4 break;
5 }
6}
Tham khảo: book_Antti Laaksonen.pdf