The Bellman-Ford Algorithm is an algorithm that computes the length of the shortest path from a vertex to every vertex in a directed graph with edge weights and no negative cycles in time and space.

Tip

This problem can also be solved by the Floyd-Warshall Algorithm in time and space.

Tip

This problem can also be solved by Johnson’s Algorithm in

  • time and space, or

  • time and space.

Algorithm 0

Lemma

Let denote the length of the shortest path from to passing through at most edges, denote the set of edges directed toward . Then

Lemma

Let denote the length of the shortest path from to , then

Applying the lemmas to find and yields an algorithm that solves the problem in time and space.

std::vector<int> bellman_ford(int n, int m, const std::vector<int> &u, const std::vector<int> &v, const std::vector<int> &w, int s) {
	std::vector dist(n, std::vector(n, inf));
	dist[0][s] = 0;
	for (int i = 1; i < n; i++) {
		dist[i] = dist[i - 1];
		for (int j = 0; j < m; j++) {
			dist[i][v[j]] = std::min(dist[i][v[j]], dist[i - 1][u[j]] + w[j]);
		}
	}
	return dist[n - 1];
}

Algorithm 1

Based on Algorithm 0, ignoring the first dimension yields an algorithm that solves the problem in time and space.

std::vector<int> bellman_ford(int n, int m, const std::vector<int> &u, const std::vector<int> &v, const std::vector<int> &w, int s) {
	std::vector dist(n, inf);
	dist[s] = 0;
	for (int i = 1; i < n; i++) {
		for (int j = 0; j < m; j++) {
			dist[v[i]] = std::min(dist[v[i]], dist[u[i]] + w[i]);
		}
	}
	return dist;
}

Algorithm 2

Based on Algorithm 1, maintaining a queue to skip unchanged values that cannot be used to update other values yields an algorithm that solves the problem in and space.

std::vector<int> bellman_ford(int n, int m, const std::vector<int> &u, const std::vector<int> &v, const std::vector<int> &w, int s) {
	std::vector<std::vector<std::pair<int, int>>> adj(n);
	for (int i = 0; i < m; i++) {
		adj[u[i]].emplace_back(v[i], w[i]);
	}
 
	std::vector dist(n, inf);
	dist[s] = 0;
	std::queue<int> q;
	q.push(s);
	std::vector vis(n, false);
	vis[s] = true;
 
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		vis[u] = false;
 
		for (auto [v, w] : adj[u]) {
			if (dist[v] > dist[u] + w) {
				dist[v] = dist[u] + w;
				if (!vis[v]) {
					q.push(v);
					vis[v] = true;
				}
			}
		}
	}
 
	return dist;
}