Algorithm Search⌘K

Proofs: Dial's algorithm

These are the human proofs of Dial's algorithm, at full length.

Dial's algorithm computes the distances full

This proof shows: correctness, termination.

Claim. Let GG be a directed graph with integer weights in {0,…,C}\{0, \ldots, C\} and a source ss. DIAL ends, and at the end d[v]=δ(s,v)d[v] = \delta(s, v) for every vv; for every v≠sv \ne s with d[v]<∞d[v] < \infty, d[v]=d[π[v]]+w(π[v],v)d[v] = d[\pi[v]] + w(\pi[v], v).

Notation. An entry is an occurrence of a vertex in a bucket; its key is the label the vertex got when the entry was added. Let KK be the multiset of keys of all entries in the buckets; left=∣K∣\text{left} = |K|.

Step 1: the window. Invariant: every key in KK lies in {i,i+1,…,i+C}\{i, i + 1, \ldots, i + C\}, and an entry with key kk is in bucket B[k mod (C+1)]B[k \bmod (C + 1)].

It holds after line L3, with K={0}K = \{0\} and i=0i = 0. Line L10 adds the key i+wi + w with 0≤w≤C0 \le w \le C, inside the window, to the right bucket. Lines L6 and L7 only remove entries. Line L5 raises ii by one only when B[i mod (C+1)]B[i \bmod (C + 1)] is empty. The C+1C + 1 values i,…,i+Ci, \ldots, i + C have distinct residues modulo C+1C + 1, so only key ii maps to that bucket; its being empty means i∉Ki \notin K, and all keys lie in {i+1,…,i+C}⊆{i+1,…,i+1+C}\{i + 1, \ldots, i + C\} \subseteq \{i + 1, \ldots, i + 1 + C\}.

Step 2: termination. In line L5, left>0\text{left} > 0, so some key k∈{i,…,i+C}k \in \{i, \ldots, i + C\} exists, and ii stops at the latest at kk. So line L5 ends. Each label drop in line L10 lowers d[v]d[v]; while uu is scanned, d[u]=id[u] = i, and a vertex is scanned only when d[u]=id[u] = i (line L7), and ii never decreases, so each vertex is scanned at most once (a second scan would need the same label at a later moment, but its entry with that key was removed and labels only fall). So line L10 runs at most mm times, there are at most m+1m + 1 entries in total, each pass of line L4 removes one, and the loop ends.

Step 3: the same run as Dijkstra. By Step 1, the bucket emptied in line L6 holds exactly the entries with key ii, and all keys are at least ii. So line L6 removes an entry of least key, as extract-min does on a binary heap holding the same entries. The key of an entry for uu satisfies d[u]≤d[u] \le key, since labels only fall; line L7 skips it exactly when $d[u] < $ key =i= i, which is the stale test of lazy-deletion Dijkstra. Lines L8 to L10 relax the edges out of uu with d[u]=id[u] = i. So the sequence of scanned vertices and label changes is that of Dijkstra's algorithm with a lazy-deletion priority queue, with ties among equal keys broken by the order inside a bucket.

Step 4: correctness. Dijkstra's algorithm with lazy deletion, with any tie-breaking, ends with d[v]=δ(s,v)d[v] = \delta(s, v) and a shortest-path tree in π\pi when all weights are nonnegative; see the proof on the correctness of Dijkstra's algorithm. For completeness, the core of it in this setting: when uu is scanned at index i=d[u]i = d[u], suppose δ(s,u)<i\delta(s, u) < i, and let PP be a shortest path to uu. Its first vertex yy not yet scanned has a scanned predecessor xx (or is ss), and the relaxation of (x,y)(x, y) when xx was scanned gave d[y]≤δ(s,x)+w(x,y)=δ(s,y)d[y] \le \delta(s, x) + w(x, y) = \delta(s, y) by induction on scan order. So an entry with key at most δ(s,y)≤δ(s,u)<i\delta(s, y) \le \delta(s, u) < i is in the buckets, against Step 1. Hence d[u]=δ(s,u)d[u] = \delta(s, u) when scanned. Unscanned vertices at the end have no entry; a reachable vertex gets an entry when its predecessor on a shortest path is scanned, so every reachable vertex is scanned, and an unreachable vertex keeps ∞\infty, since every finite label is the weight of a walk from ss. When d[v]d[v] was last set, it was d[π[v]]+w(π[v],v)d[\pi[v]] + w(\pi[v], v) with d[π[v]]d[\pi[v]] already final, which gives the tree equation. ■\blacksquare

Back to Dial's algorithm