The Path-Relaxation Property & Negative Cycle Witness
Let a shortest simple path from $s$ to $v$ be $P = \langle v_0, v_1, \dots, v_k \rangle$ where $v_0 = s$, $v_k = v$, and $k \le |V| - 1$.
If $G = (V, E)$ contains no negative-weight cycles reachable from $s$, then after $i$ complete passes of relaxing every edge in $E$, for every vertex $v$ that has a shortest path from $s$ consisting of at most $i$ edges, $d[v] = \delta(s, v)$.
Corollary (Negative Cycle Certificate on Pass $V$): Since every simple path has $\le |V| - 1$ edges, if no negative cycle is reachable from $s$, no distance $d[v]$ can decrease on the $|V|$-th pass. Conversely, if any edge $(u, v)$ satisfies $d[u] + w(u, v) < d[v]$ on pass $|V|$, then $v$ is reachable from a negative-weight cycle! Walking backward $|V|$ steps along $\text{parent}[\cdot]$ pointers from $v$ is guaranteed to land strictly inside the negative cycle itself.
1. Reconstructing the Exact Negative Cycle
Notice a subtle trap: if vertex $v$ is relaxed on pass $V$, $v$ might not lie on the negative cycle itself—it might merely be a downstream vertex reachable from a negative cycle $C$. However, because the predecessor subgraph traced backward from $v$ has out-degree $1$ in the reversed sense and was updated within the last $V$ steps, executing for (int i = 0; i < V; ++i) x = parent[x]; walks backward out of the downstream tail and is guaranteed to place $x$ on the cycle $C$. From there, following $\text{parent}$ until returning to $x$ extracts the exact cycle.
2. Systems of Difference Constraints ($x_v - x_u \le w$)
Suppose a scheduling or VLSI layout problem gives $M$ linear inequalities of the form:
$$x_v - x_u \le w_{u,v} \iff x_v \le x_u + w_{u,v}$$Compare this directly with the shortest-path triangle inequality $\delta(s, v) \le \delta(s, u) + w(u, v)$! By creating a directed edge $(u, v)$ of weight $w_{u,v}$ for each constraint $x_v - x_u \le w_{u,v}$ and adding a virtual source $s^*$ with $0$-weight edges to all variables, the system of inequalities has a feasible solution if and only if the constraint graph has no negative cycle, and setting $x_v = \delta(s^*, v)$ is a valid solution!
Witness negative cycles on the V-th relaxation round of Bellman-Ford, inspect Floyd-Warshall’s in-place DP matrix D^(k)[i][j] = min(D[i][j], D[i][k]+D[k][j]), and reweight negative edges to non-negative via Johnson potentials w_hat(u,v) = w(u,v) + h(u) - h(v) ≥ 0.
Invariant & State
Because Bellman-Ford relaxes every edge indiscriminately on each pass, iterating over a single contiguous std::vector<Edge> of 16-byte {u, v, w} structs is $3\times$ faster than nested adjacency list loops. Conversely, the Queue-based Bellman-Ford variant (SPFA) has worst-case $O(V \cdot E)$ complexity and is easily forced into $O(V \cdot E)$ with terrible random-access cache misses by grid/ladder anti-SPFA test cases.
Complexity Matrix
| Algorithm / Problem | Average / Best Case | Worst-Case Time | Space Complexity |
|---|---|---|---|
| Bellman-Ford (with Early Exit) | O(k · E) ($k \le V$) | O(V · E) | O(V) |
| SPFA (Queue-Based Moore) | O(E) (random graphs) | O(V · E) (adversarial grids) | O(V) |
| Difference Constraints ($M$ inequalities) | O(N + M) | O(N · M) | O(N + M) |
Production Implementation: Bellman-Ford with Exact Negative Cycle Reconstruction
#include <vector>
#include <algorithm>
struct BFEdge {
int u, v;
long long weight;
};
// Finds any negative cycle in the graph (initializing dist to 0 acts as a virtual super-source!)
std::vector<int> findNegativeCycle(int n, const std::vector<BFEdge>& edges) {
std::vector<long long> dist(n, 0);
std::vector<int> parent(n, -1);
int lastRelaxed = -1;
for (int step = 0; step < n; ++step) {
lastRelaxed = -1;
for (const auto& e : edges) {
if (dist[e.u] + e.weight < dist[e.v]) {
dist[e.v] = dist[e.u] + e.weight;
parent[e.v] = e.u;
lastRelaxed = e.v;
}
}
if (lastRelaxed == -1) return {}; // Early exit: no negative cycle exists
}
// Walk backward n steps to guarantee landing strictly inside the negative cycle
int cycleNode = lastRelaxed;
for (int i = 0; i < n; ++i) {
cycleNode = parent[cycleNode];
}
std::vector<int> cycle;
for (int cur = cycleNode;; cur = parent[cur]) {
cycle.push_back(cur);
if (cur == cycleNode && cycle.size() > 1) break;
}
std::reverse(cycle.begin(), cycle.end());
return cycle;
}
INF Causes Signed Overflow with Negative EdgesWhen finding single-source shortest paths from $s$ (where unreachable vertices start at dist[u] = INF), if edge $(u, v)$ has weight $-10$ and $u$ is unreachable ($d[u] = \text{INF}$), evaluating dist[u] + (-10) < dist[v] will evaluate to INF - 10 < INF (True!), propagating fake finite distances through unreachable components! Always guard single-source relaxations with if (dist[e.u] != INF && dist[e.u] + e.weight < dist[e.v]).