Number of paths of fixed length / Shortest paths of fixed length¶
The following article describes solutions to these two problems built on the same idea:
reduce the problem to the construction of matrix and compute the solution with the usual matrix multiplication or with a modified multiplication.
We are given a directed, unweighted graph <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>G</mi></math>$G$ with <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>n</mi></math>$n$ vertices and we are given an integer <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$.
The task is the following:
for each pair of vertices <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mi>i</mi><mo>,</mo><mi>j</mi><mo stretchy="false">)</mo></math>$(i, j)$ we have to find the number of paths of length <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$ between these vertices.
Paths don't have to be simple, i.e. vertices and edges can be visited any number of times in a single path.
We assume that the graph is specified with an adjacency matrix, i.e. the matrix <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>G</mi><mo stretchy="false">[</mo><mo stretchy="false">]</mo><mo stretchy="false">[</mo><mo stretchy="false">]</mo></math>$G[][]$ of size <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>n</mi><mo>×</mo><mi>n</mi></math>$n \times n$, where each element <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>G</mi><mo stretchy="false">[</mo><mi>i</mi><mo stretchy="false">]</mo><mo stretchy="false">[</mo><mi>j</mi><mo stretchy="false">]</mo></math>$G[i][j]$ equal to <math xmlns="http://www.w3.org/1998/Math/MathML"><mn>1</mn></math>$1$ if the vertex <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>i</mi></math>$i$ is connected with <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>j</mi></math>$j$ by an edge, and <math xmlns="http://www.w3.org/1998/Math/MathML"><mn>0</mn></math>$0$ is they are not connected by an edge.
The following algorithm works also in the case of multiple edges:
if some pair of vertices <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mi>i</mi><mo>,</mo><mi>j</mi><mo stretchy="false">)</mo></math>$(i, j)$ is connected with <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>m</mi></math>$m$ edges, then we can record this in the adjacency matrix by setting <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>G</mi><mo stretchy="false">[</mo><mi>i</mi><mo stretchy="false">]</mo><mo stretchy="false">[</mo><mi>j</mi><mo stretchy="false">]</mo><mo>=</mo><mi>m</mi></math>$G[i][j] = m$.
Also the algorithm works if the graph contains loops (a loop is an edge that connect a vertex with itself).
It is obvious that the constructed adjacency matrix if the answer to the problem for the case <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi><mo>=</mo><mn>1</mn></math>$k = 1$.
It contains the number of paths of length <math xmlns="http://www.w3.org/1998/Math/MathML"><mn>1</mn></math>$1$ between each pair of vertices.
We will build the solution iteratively:
Let's assume we know the answer for some <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$.
Here we describe a method how we can construct the answer for <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi><mo>+</mo><mn>1</mn></math>$k + 1$.
Denote by <math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>C</mi><mi>k</mi></msub></math>$C_k$ the matrix for the case <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$, and by <math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>C</mi><mrow data-mjx-texclass="ORD"><mi>k</mi><mo>+</mo><mn>1</mn></mrow></msub></math>$C_{k+1}$ the matrix we want to construct.
With the following formula we can compute every entry of <math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>C</mi><mrow data-mjx-texclass="ORD"><mi>k</mi><mo>+</mo><mn>1</mn></mrow></msub></math>$C_{k+1}$:
It is easy to see that the formula computes nothing other than the product of the matrices <math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>C</mi><mi>k</mi></msub></math>$C_k$ and <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>G</mi></math>$G$:
It remains to note that the matrix products can be raised to a high power efficiently using Binary exponentiation.
This gives a solution with <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>O</mi><mo stretchy="false">(</mo><msup><mi>n</mi><mn>3</mn></msup><mi>log</mi><mo data-mjx-texclass="NONE"></mo><mi>k</mi><mo stretchy="false">)</mo></math>$O(n^3 \log k)$ complexity.
We are given a directed weighted graph <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>G</mi></math>$G$ with <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>n</mi></math>$n$ vertices and an integer <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$.
For each pair of vertices <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mi>i</mi><mo>,</mo><mi>j</mi><mo stretchy="false">)</mo></math>$(i, j)$ we have to find the length of the shortest path between <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>i</mi></math>$i$ and <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>j</mi></math>$j$ that consists of exactly <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$ edges.
We assume that the graph is specified by an adjacency matrix, i.e. via the matrix <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>G</mi><mo stretchy="false">[</mo><mo stretchy="false">]</mo><mo stretchy="false">[</mo><mo stretchy="false">]</mo></math>$G[][]$ of size <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>n</mi><mo>×</mo><mi>n</mi></math>$n \times n$ where each element <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>G</mi><mo stretchy="false">[</mo><mi>i</mi><mo stretchy="false">]</mo><mo stretchy="false">[</mo><mi>j</mi><mo stretchy="false">]</mo></math>$G[i][j]$ contains the length of the edges from the vertex <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>i</mi></math>$i$ to the vertex <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>j</mi></math>$j$.
If there is no edge between two vertices, then the corresponding element of the matrix will be assigned to infinity <math xmlns="http://www.w3.org/1998/Math/MathML"><mi mathvariant="normal">∞</mi></math>$\infty$.
It is obvious that in this form the adjacency matrix is the answer to the problem for <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi><mo>=</mo><mn>1</mn></math>$k = 1$.
It contains the lengths of shortest paths between each pair of vertices, or <math xmlns="http://www.w3.org/1998/Math/MathML"><mi mathvariant="normal">∞</mi></math>$\infty$ if a path consisting of one edge doesn't exist.
Again we can build the solution to the problem iteratively:
Let's assume we know the answer for some <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$.
We show how we can compute the answer for <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi><mo>+</mo><mn>1</mn></math>$k+1$.
Let us denote <math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>L</mi><mi>k</mi></msub></math>$L_k$ the matrix for <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$ and <math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>L</mi><mrow data-mjx-texclass="ORD"><mi>k</mi><mo>+</mo><mn>1</mn></mrow></msub></math>$L_{k+1}$ the matrix we want to build.
Then the following formula computes each entry of <math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>L</mi><mrow data-mjx-texclass="ORD"><mi>k</mi><mo>+</mo><mn>1</mn></mrow></msub></math>$L_{k+1}$:
When looking closer at this formula, we can draw an analogy with the matrix multiplication:
in fact the matrix <math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>L</mi><mi>k</mi></msub></math>$L_k$ is multiplied by the matrix <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>G</mi></math>$G$, the only difference is that instead in the multiplication operation we take the minimum instead of the sum.
It remains to note that we also can compute this exponentiation efficiently with Binary exponentiation, because the modified multiplication is obviously associative.
So also this solution has <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>O</mi><mo stretchy="false">(</mo><msup><mi>n</mi><mn>3</mn></msup><mi>log</mi><mo data-mjx-texclass="NONE"></mo><mi>k</mi><mo stretchy="false">)</mo></math>$O(n^3 \log k)$ complexity.
Generalization of the problems for paths with length up to <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$¶
The above solutions solve the problems for a fixed <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$.
However the solutions can be adapted for solving problems for which the paths are allowed to contain no more than <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$ edges.
This can be done by slightly modifying the input graph.
We duplicate each vertex:
for each vertex <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>v</mi></math>$v$ we create one more vertex <math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mi>v</mi><mo data-mjx-alternate="1">′</mo></msup></math>$v'$ and add the edge <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mi>v</mi><mo>,</mo><msup><mi>v</mi><mo data-mjx-alternate="1">′</mo></msup><mo stretchy="false">)</mo></math>$(v, v')$ and the loop <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><msup><mi>v</mi><mo data-mjx-alternate="1">′</mo></msup><mo>,</mo><msup><mi>v</mi><mo data-mjx-alternate="1">′</mo></msup><mo stretchy="false">)</mo></math>$(v', v')$.
The number of paths between <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>i</mi></math>$i$ and <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>j</mi></math>$j$ with at most <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$ edges is the same number as the number of paths between <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>i</mi></math>$i$ and <math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mi>j</mi><mo data-mjx-alternate="1">′</mo></msup></math>$j'$ with exactly <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi><mo>+</mo><mn>1</mn></math>$k + 1$ edges, since there is a bijection that maps every path <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">[</mo><msub><mi>p</mi><mn>0</mn></msub><mo>=</mo><mi>i</mi><mo>,</mo><mtext> </mtext><msub><mi>p</mi><mn>1</mn></msub><mo>,</mo><mtext> </mtext><mo>…</mo><mo>,</mo><mtext> </mtext><msub><mi>p</mi><mrow data-mjx-texclass="ORD"><mi>m</mi><mo>−</mo><mn>1</mn></mrow></msub><mo>,</mo><mtext> </mtext><msub><mi>p</mi><mi>m</mi></msub><mo>=</mo><mi>j</mi><mo stretchy="false">]</mo></math>$[p_0 = i,~p_1,~\ldots,~p_{m-1},~p_m = j]$ of length <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>m</mi><mo>≤</mo><mi>k</mi></math>$m \le k$ to the path <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">[</mo><msub><mi>p</mi><mn>0</mn></msub><mo>=</mo><mi>i</mi><mo>,</mo><mtext> </mtext><msub><mi>p</mi><mn>1</mn></msub><mo>,</mo><mtext> </mtext><mo>…</mo><mo>,</mo><mtext> </mtext><msub><mi>p</mi><mrow data-mjx-texclass="ORD"><mi>m</mi><mo>−</mo><mn>1</mn></mrow></msub><mo>,</mo><mtext> </mtext><msub><mi>p</mi><mi>m</mi></msub><mo>=</mo><mi>j</mi><mo>,</mo><msup><mi>j</mi><mo data-mjx-alternate="1">′</mo></msup><mo>,</mo><mo>…</mo><mo>,</mo><msup><mi>j</mi><mo data-mjx-alternate="1">′</mo></msup><mo stretchy="false">]</mo></math>$[p_0 = i,~p_1,~\ldots,~p_{m-1},~p_m = j, j', \ldots, j']$ of length <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi><mo>+</mo><mn>1</mn></math>$k + 1$.
The same trick can be applied to compute the shortest paths with at most <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$ edges.
We again duplicate each vertex and add the two mentioned edges with weight <math xmlns="http://www.w3.org/1998/Math/MathML"><mn>0</mn></math>$0$.