This is a blog for cp newbies (like me).
For a long time I think the Dijkstra algorithm (dij) only has two usages:
(1) Calculate the distance between the vertices when the weights of edges are non-negative.
(2) (Minimax) Given a path $$$p = x_1x_2...x_n$$$, define $$$f(p) := \max_{i=1}^{n-1}d(x_i, x_{i+1})$$$. Given source vertex $$$s$$$ and target vertex $$$t$$$, dij is able to calculate $$$min \{f(p)|p\,\text{is a s-t path}\}$$$.
However, dij works for a function class, not only the sum/max functions. The sum/max functions are only the two most frequently used members of this function class, but the function class is far larger than these two. Once the function $$$f$$$ satisfies several mandatory properties, you could use dij. The word "function class" is like an abstract class in C++:
struct f{
virtual void property1() = 0;
virtual void property2() = 0;
virtual void property3() = 0;
//...
};//dijkstra function.
dij(f);
The graph $$$G=(V(G),E(G))$$$. WLOG we assume $$$G$$$ is connected. There is a non-empty source set $$$S \in V(G)$$$ that needs not be a singleton. A path $$$p$$$ is a vector of vertices $$$\{v_1,v_2,...,v_n\}$$$ and the function f is a function that maps paths to real numbers: path→R. To be brief, $$$f(\{v_1,v_2,...,v_n\})$$$ is shorten to $$$f(v_1,v_2,...,v_n)$$$. We say that dij works for f if $$$\forall v \in V(G)$$$, dij correctly computes $$$d(v) := \min f(\{p \mid p\,\text{is a S-v path}\})$$$. f should satisfy three properties that are also sufficient:
(1, induction base) ∀s∈S, f(s) should be correctly initialized.
(2, Extension property) $$$\forall p$$$, for every vertex $$$v$$$ adjacent to the end of $$$p$$$ (p.back()
), $$$f(p \cup v) \geq f(p)$$$.
(3, dynamic programming (dp) property) If path $$$p, q$$$ has the same end (i.e., p.back()==q.back()
) and $$$f(p) \geq f(q)$$$, then for every vertex $$$v$$$ adjacent to p.back()
, $$$f(p \cup v) \geq f(q \cup v)$$$.
The necessity of the induction base is obvious. Otherwise, the $$$f$$$(source vertices) are wrong. For the second property, it is well known that the sum version of dij (shortest path) does not work for edges with negative cost (but the max version works!). For the dp property, let's consider the following example:
In this example $$$f(p):=\sum\limits_{i=1}^{n-1} i \text{dis}(v_i, v_{i+1})$$$. $$$f(ABC) = 1+4*2 = 9$$$; $$$f(AC)=10$$$; $$$f(ABCD) = 1+4*2 + 5*3=24$$$, $$$f(ACD)=10+5*2=20$$$. Since $$$f(ABC) < f(AC),\,f(ABCD) > f(ACD)$$$, $$$f$$$ violates the dp property. In this case dij does not work, because dij uses ABC to slack D, giving a wrong result $$$24$$$ instead of the correct answer $$$20$$$.
We briefly review the outline of the dij:
define a distance array d. Initially fill d with INF;
Initialize f(s), d(s) for all source vertices s in S;
define a set T which is initially S;
int i = 0;
while T != V(G){
choose a vertex u that is not in T with the lowest d value; //Choice step
for every vertice v not in T and adjacent to u, update d(v) as d(v) = min(d(v), f([path from S to u] + v)). //You can record the shortest path from S to v here;
T.insert(u);
i++;
}
Here, I want to illustrate the importance of these properties by proving the correctness of the algorithm. We denote $$$d(v)$$$ as the real value of the shortest path (i.e., $$$\min f(\{p \mid p\,\text{is a S-v path}\}$$$), and $$$h(v)$$$ as the value calculated by dij. We want to prove $$$\forall v \in V(G),\,d(v) = h(v)$$$.
In the induction step, the $$$d$$$ is correctly computed for every source vertex. In the $$$i$$$-th frame, a vertex $$$u$$$ is chosen in the choice step. We assume that for every $$$u_j$$$ chosen in the $$$0,\,1,\,2...\,i-1$$$, $$$d(u_j) = h(u_j)$$$.