Graph Reconstruction

Floyd-Warshall takes a graph and produces a distance matrix. What about the reverse? Given a distance matrix, can you recover the graph?
This is the inverse of shortest-path computation. And it turns out the answer is clean, elegant, and deeply connected to the edge forensics from the previous lesson.
The Problem: ARC083-B Restoring Road Network
Given an \(N \times N\) matrix \(A\) where \(A[i][j]\) is the claimed shortest distance between cities \(i\) and \(j\). Determine:
- Does a weighted undirected graph exist whose all-pairs shortest distances equal \(A\)?
- If yes, what is the minimum total edge weight among all such graphs?
Constraints: \(N \leq 300\), \(A[i][j] \leq 10^9\).
Step 1: Validate the Matrix
A distance matrix must satisfy three properties:
Zero diagonal. \(A[i][i] = 0\) for all \(i\).
Symmetry. \(A[i][j] = A[j][i]\) for all \(i, j\).
Triangle inequality. \(A[i][j] \leq A[i][k] + A[k][j]\) for all \(i, j, k\).
If any of these fail, no valid graph exists. Output \(-1\).
bool valid = true;
for (int i = 0; i < N && valid; i++) {
if (A[i][i] != 0) valid = false;
for (int j = 0; j < N && valid; j++) {
if (A[i][j] != A[j][i]) valid = false;
for (int k = 0; k < N && valid; k++) {
if (A[i][j] > A[i][k] + A[k][j]) valid = false;
}
}
}
if (!valid) { cout << -1 << "\n"; return 0; }
Gotcha. The triangle inequality check is strict: \(A[i][j] > A[i][k] + A[k][j]\), not \(\geq\). Equality is fine --- it just means there's a multi-hop shortest path.
Step 2: Find the Minimum Graph
Now we know a valid graph exists. Which edges should it contain?
Consider the potential edge \((i, j)\) with weight \(A[i][j]\). This edge is necessary only if no intermediate vertex \(k\) achieves \(A[i][k] + A[k][j] = A[i][j]\).
If some \(k\) achieves it, the shortest path from \(i\) to \(j\) can go through \(k\) without a direct edge. The edge is redundant.
ll total = 0;
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
bool needed = true;
for (int k = 0; k < N; k++) {
if (k == i || k == j) continue;
if (A[i][k] + A[k][j] == A[i][j]) {
needed = false;
break;
}
}
if (needed) total += A[i][j];
}
}
cout << total << "\n";
Key insight. This is exactly the edge classification from Lesson 2, but in reverse. In Lesson 2, we had a graph and asked which edges were necessary. Here, we have distances and construct only the necessary edges. Same test, opposite direction.
Why This Works
Claim: the graph containing exactly the necessary edges produces distance matrix \(A\).
Proof sketch:
-
Every necessary edge \((i, j)\) has weight \(A[i][j]\), so \(\text{dist}(i, j) \leq A[i][j]\).
-
For a redundant pair \((i, j)\), some \(k\) satisfies \(A[i][k] + A[k][j] = A[i][j]\). By induction, the necessary edges already produce \(\text{dist}(i, k) = A[i][k]\) and \(\text{dist}(k, j) = A[k][j]\). So \(\text{dist}(i, j) \leq A[i][j]\).
-
No distance can be shorter than \(A[i][j]\) because every edge has weight \(\geq A[u][v]\) (we only use weights from the matrix), and the triangle inequality holds.
Therefore \(\text{dist}(i, j) = A[i][j]\) for all pairs.
Trace: 4-Node Distance Matrix
Input matrix \(A\):
| 0 | 1 | 2 | 3 | |
|---|---|---|---|---|
| 0 | 0 | 1 | 2 | 3 |
| 1 | 1 | 0 | 1 | 2 |
| 2 | 2 | 1 | 0 | 1 |
| 3 | 3 | 2 | 1 | 0 |
Validation: triangle inequality holds. For example, \(A[0][3] = 3 \leq A[0][1] + A[1][3] = 1 + 2 = 3\). Check.
Edge necessity check:
| Pair (i,j) | A[i][j] | Bypass via k? | Necessary? |
|---|---|---|---|
| (0,1) | 1 | k=2: 2+1=3 > 1. k=3: 3+2=5 > 1. | Yes |
| (0,2) | 2 | k=1: 1+1=2 = 2. Bypass found. | No |
| (0,3) | 3 | k=1: 1+2=3 = 3. Bypass found. | No |
| (1,2) | 1 | k=0: 1+2=3 > 1. k=3: 2+1=3 > 1. | Yes |
| (1,3) | 2 | k=2: 1+1=2 = 2. Bypass found. | No |
| (2,3) | 1 | k=0: 2+3=5 > 1. k=1: 1+2=3 > 1. | Yes |
Necessary edges: (0,1) w=1, (1,2) w=1, (2,3) w=1.
Total weight: \(1 + 1 + 1 = 3\).
The minimum graph is a path: \(0 - 1 - 2 - 3\).
The Floyd-Warshall Duality
Floyd-Warshall and graph reconstruction are inverse operations:
| Operation | Input | Output |
|---|---|---|
| Floyd-Warshall | Edge list (graph) | Distance matrix |
| Graph reconstruction | Distance matrix | Edge list (minimum graph) |
The reconstruction uses the exact same triple loop structure as Floyd-Warshall but asks the opposite question. Floyd asks: "can vertex \(k\) improve the path from \(i\) to \(j\)?" Reconstruction asks: "does vertex \(k\) make the direct edge from \(i\) to \(j\) unnecessary?"
Key insight. If you understand Floyd-Warshall, you already understand graph reconstruction. They're the same algorithm reading the same data with opposite intent.
Full Solution Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
int N;
cin >> N;
vector<vector<ll>> A(N, vector<ll>(N));
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
cin >> A[i][j];
// Validate
for (int i = 0; i < N; i++) {
if (A[i][i] != 0) { cout << -1 << "\n"; return 0; }
for (int j = 0; j < N; j++) {
if (A[i][j] != A[j][i]) { cout << -1 << "\n"; return 0; }
for (int k = 0; k < N; k++) {
if (A[i][j] > A[i][k] + A[k][j]) {
cout << -1 << "\n";
return 0;
}
}
}
}
// Find minimum graph
ll total = 0;
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
bool needed = true;
for (int k = 0; k < N; k++) {
if (k == i || k == j) continue;
if (A[i][k] + A[k][j] == A[i][j]) {
needed = false;
break;
}
}
if (needed) total += A[i][j];
}
}
cout << total << "\n";
return 0;
}
Complexity
- Validation: \(O(N^3)\).
- Edge necessity: \(O(N^3)\) (for each of \(O(N^2)\) pairs, check \(O(N)\) intermediates).
- Total: \(O(N^3)\). Same as Floyd-Warshall itself.
For \(N = 300\), that's \(2.7 \times 10^7\) operations. Comfortable.
Edge Cases
Complete graph distances. If \(A[i][j] = 1\) for all \(i \neq j\), every edge is necessary (no bypass can improve on weight 1). The minimum graph is the complete graph with \(\binom{N}{2}\) edges, total weight \(\binom{N}{2}\).
Star graph distances. If \(A[0][j] = 1\) for all \(j\) and \(A[i][j] = 2\) for \(i, j \neq 0\), only the \(N-1\) edges from node 0 are necessary. Every pair \((i, j)\) with \(i, j \neq 0\) has a bypass through node 0: \(A[i][0] + A[0][j] = 1 + 1 = 2 = A[i][j]\).
Invalid matrix. \(A[0][1] = 1\), \(A[1][2] = 1\), \(A[0][2] = 5\). Triangle inequality violated: \(5 > 1 + 1\). Output \(-1\).
Exercises
-
If the distance matrix represents a tree, how many edges will the reconstruction produce? Prove it.
-
Can reconstruction produce a graph with more edges than the original? When?
-
Given a distance matrix for a directed graph (\(A[i][j] \neq A[j][i]\) possible), how does the reconstruction change?
Problems
| Problem | Link | Difficulty |
|---|---|---|
| ARC083-B -- Restoring Road Network | atcoder.jp/contests/arc083/tasks/arc083_b | Medium |