Shortest Paths II: Bellman-Ford, Floyd-Warshall, A*
Bellman-Ford, Floyd-Warshall, A*
1. Beyond Dijkstra
Dijkstra is fast but breaks on negative edges. Bellman-Ford handles them in O(VE), and even detects negative cycles. Floyd-Warshall finds shortest paths between every pair of vertices in O(V³). A* uses a heuristic to focus search on promising directions, dramatically faster on geographic / grid problems.
2. Bellman-Ford — V−1 Relaxation Rounds
Initialise dist[src] = 0, others = ∞. Relax every edge V − 1 times. After V − 1 rounds, shortest distances are final (a path uses ≤ V − 1 edges). One more relaxation round that still improves something proves a negative cycle.
#include <bits/stdc++.h>
using namespace std;
int main() {
int V = 5;
vector<tuple<int,int,int>> e = {
{0,1, 6}, {0,2, 7}, {1,2, 8}, {1,3, 5},
{1,4,-4}, {2,3,-3}, {2,4, 9}, {3,1,-2}, {4,3, 7}
};
vector<long long> dist(V, LLONG_MAX);
dist[0] = 0;
for (int i = 0; i < V - 1; i++)
for (auto [u, v, w] : e)
if (dist[u] != LLONG_MAX && dist[u] + w < dist[v])
dist[v] = dist[u] + w;
bool neg = false;
for (auto [u, v, w] : e)
if (dist[u] != LLONG_MAX && dist[u] + w < dist[v]) neg = true;
if (neg) cout << "negative cycle\n";
else for (int i = 0; i < V; i++)
cout << "dist[0..." << i << "] = " << dist[i] << "\n";
}
3. Floyd-Warshall — All Pairs in O(V³)
Three nested loops on the V × V distance matrix:
for k in 0..V−1: for i: for j: dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
The order matters: k is the outer loop, representing "I'm now allowed to use intermediate vertices ≤ k". After all V iterations, dist[i][j] is the true shortest path.
#include <bits/stdc++.h>
using namespace std;
const long long INF = 1e18;
int main() {
int V = 4;
vector<vector<long long>> d(V, vector<long long>(V, INF));
for (int i = 0; i < V; i++) d[i][i] = 0;
vector<tuple<int,int,int>> e = {{0,1,5},{0,3,10},{1,2,3},{2,3,1}};
for (auto [u, v, w] : e) d[u][v] = w;
for (int k = 0; k < V; k++)
for (int i = 0; i < V; i++)
for (int j = 0; j < V; j++)
if (d[i][k] + d[k][j] < d[i][j])
d[i][j] = d[i][k] + d[k][j];
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) cout << (d[i][j] == INF ? -1 : d[i][j]) << "\t";
cout << "\n";
}
}
4. Johnson's Algorithm — Negative-Edge All-Pairs
For sparse graphs with negative edges, Johnson's reweights edges via Bellman-Ford to non-negative, then runs Dijkstra from each vertex. Total: O(V·E·log V) — beats Floyd's V³ when E ≪ V². The reweighting trick uses node potentials.
5. A* — Heuristic Search
A* is Dijkstra with a heuristic h(v) estimating the remaining cost to the goal.
Pop the vertex with smallest g(v) + h(v) (cost so far + heuristic). If h is
admissible (never overestimates), A* finds the optimal path; if also
consistent, no vertex is reopened.
6. Practice Problems
-
Cheapest flights with at most K stops via bounded Bellman-Ford.K stops-এর মধ্যে cheapest flight — bounded Bellman-Ford।
✨ Show Answer (উত্তর দেখুন)
Approach: run K+1 relaxation rounds (instead of V−1). Use a previous dist array per round to avoid using more than K stops in one round.
-
Detect arbitrage in currency exchange rates by negative-cycle detection.মুদ্রা arbitrage — negative cycle detection।
✨ Show Answer (উত্তর দেখুন)
Approach: for rate r(u→v), use weight −log(r). A cycle whose sum is negative means product of rates > 1 → arbitrage. Run Bellman-Ford and check the V-th relaxation.
-
Transitive closure of a DAG (or any digraph) using Floyd-Warshall variant.Transitive closure — Floyd-Warshall।
✨ Show Answer (উত্তর দেখুন)
Approach: use boolean matrix;
reach[i][j] |= reach[i][k] && reach[k][j]. O(V³). For V ≤ 1024, use std::bitset to speed up by 64×. -
Shortest path in a grid with non-negative weights using A* with Manhattan heuristic.Grid-এ A* — Manhattan heuristic।
✨ Show Answer (উত্তর দেখুন)
Approach: priority queue keyed by
g + h. h(r,c) = |r − goalR| + |c − goalC|. Manhattan is admissible for 4-connected grids with unit costs. -
When would you choose Bellman-Ford over Dijkstra even on a non-negative graph?Non-negative graph-এ কখনো Bellman-Ford?
✨ Show Answer (উত্তর দেখুন)
Answer: rarely — Dijkstra is faster. But if the graph is dynamic and you need to add a single negative edge later, Bellman-Ford is naturally extensible. Also, Bellman-Ford is parallelisable across edges; Dijkstra's PQ is harder to parallelise.
-
Why is the order
k → i → jin Floyd-Warshall correct?Floyd-Warshall-এ লুপ-অর্ডার গুরুত্বপূর্ণ কেন?✨ Show Answer (উত্তর দেখুন)
Answer: after the k-th outer iteration, dist[i][j] = shortest path using intermediate nodes only from {0, …, k}. Inductive proof: when we admit k as a new intermediate, the new shortest path either avoids k (already in dist[i][j]) or goes i → k → j (which is dist[i][k] + dist[k][j] computed in earlier iterations).
Summary — Module 28
Bellman-Ford handles negative edges in O(VE) and detects negative cycles. Floyd-Warshall answers all-pairs in O(V³). Johnson's reweights for sparse graphs. A* uses a heuristic to beat Dijkstra on goal-directed problems. Each tool has a niche — pick by graph size and edge weights.