Paths in a grid
This commit is contained in:
parent
7e729e8333
commit
355aef958e
113
chapter10.tex
113
chapter10.tex
|
@ -516,6 +516,119 @@ with $N=64$ (\texttt{long long} numbers).
|
||||||
|
|
||||||
\section{Dynamic programming}
|
\section{Dynamic programming}
|
||||||
|
|
||||||
|
Bit operations provide an efficient way to
|
||||||
|
implement dynamic programming algorithms
|
||||||
|
whose states contain subsets of elements,
|
||||||
|
because such states can be stored as integers.
|
||||||
|
In particular, information about all subsets
|
||||||
|
of $n$ elements can be stored in an array like
|
||||||
|
\begin{lstlisting}
|
||||||
|
int value[1<<n];
|
||||||
|
\end{lstlisting}
|
||||||
|
The following code also has an useful property:
|
||||||
|
\begin{lstlisting}
|
||||||
|
for (int b = 0; b < (1<<n); b++) {
|
||||||
|
// code
|
||||||
|
}
|
||||||
|
\end{lstlisting}
|
||||||
|
If we go through subsets in this order,
|
||||||
|
we always process subset $A$ before subset $B$
|
||||||
|
if $A \subset B$, which may be useful
|
||||||
|
in dynamic programming.
|
||||||
|
|
||||||
|
Next we discuss some examples where bit operations
|
||||||
|
and dynamic programming can be combined.
|
||||||
|
|
||||||
|
\subsubsection{Paths in a grid}
|
||||||
|
|
||||||
|
As a first example, consider a problem
|
||||||
|
where an $n \times n$ grid is given such that
|
||||||
|
each square contains an integer $0 \ldots k$.
|
||||||
|
Our task is to check if there is a path from the upper-left
|
||||||
|
corner to the lower-right corner
|
||||||
|
such that we only move right and down
|
||||||
|
and each integer $0 \ldots k$ appears on the path.
|
||||||
|
|
||||||
|
For example, the following path contains all
|
||||||
|
integers $0 \ldots 4$:
|
||||||
|
\begin{center}
|
||||||
|
\begin{tikzpicture}[scale=.65]
|
||||||
|
\begin{scope}
|
||||||
|
\fill [color=lightgray] (0, 9) rectangle (1, 8);
|
||||||
|
\fill [color=lightgray] (0, 8) rectangle (1, 7);
|
||||||
|
\fill [color=lightgray] (1, 8) rectangle (2, 7);
|
||||||
|
\fill [color=lightgray] (1, 7) rectangle (2, 6);
|
||||||
|
\fill [color=lightgray] (2, 7) rectangle (3, 6);
|
||||||
|
\fill [color=lightgray] (3, 7) rectangle (4, 6);
|
||||||
|
\fill [color=lightgray] (4, 7) rectangle (5, 6);
|
||||||
|
\fill [color=lightgray] (4, 6) rectangle (5, 5);
|
||||||
|
\fill [color=lightgray] (4, 5) rectangle (5, 4);
|
||||||
|
\draw (0, 4) grid (5, 9);
|
||||||
|
\node at (0.5,8.5) {2};
|
||||||
|
\node at (1.5,8.5) {0};
|
||||||
|
\node at (2.5,8.5) {5};
|
||||||
|
\node at (3.5,8.5) {3};
|
||||||
|
\node at (4.5,8.5) {1};
|
||||||
|
\node at (0.5,7.5) {0};
|
||||||
|
\node at (1.5,7.5) {1};
|
||||||
|
\node at (2.5,7.5) {4};
|
||||||
|
\node at (3.5,7.5) {2};
|
||||||
|
\node at (4.5,7.5) {0};
|
||||||
|
\node at (0.5,6.5) {3};
|
||||||
|
\node at (1.5,6.5) {0};
|
||||||
|
\node at (2.5,6.5) {2};
|
||||||
|
\node at (3.5,6.5) {4};
|
||||||
|
\node at (4.5,6.5) {1};
|
||||||
|
\node at (0.5,5.5) {6};
|
||||||
|
\node at (1.5,5.5) {5};
|
||||||
|
\node at (2.5,5.5) {0};
|
||||||
|
\node at (3.5,5.5) {1};
|
||||||
|
\node at (4.5,5.5) {3};
|
||||||
|
\node at (0.5,4.5) {0};
|
||||||
|
\node at (1.5,4.5) {2};
|
||||||
|
\node at (2.5,4.5) {3};
|
||||||
|
\node at (3.5,4.5) {3};
|
||||||
|
\node at (4.5,4.5) {1};
|
||||||
|
\end{scope}
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
We assume that the rows and columns are numbered
|
||||||
|
from 1 to $n$. Moreover, let $\texttt{value}[x][y]$
|
||||||
|
denote the value at position $(x,y)$.
|
||||||
|
The problem can be solved in $O(n^2 2^k)$ time
|
||||||
|
by defining a function $\texttt{possible}[x][y][S]$
|
||||||
|
whose value is true exactly when there is a path
|
||||||
|
from the upper-left square to square $(x,y)$ such that
|
||||||
|
all values in $S$ appear on the path.
|
||||||
|
Thus, $\texttt{possible}[n][n][\{0 \ldots k\}]$
|
||||||
|
tells us whether a desired path exists.
|
||||||
|
The function values can be calculated using
|
||||||
|
the following recurrence:
|
||||||
|
\begin{equation*}
|
||||||
|
\begin{aligned}
|
||||||
|
\texttt{possible}[x][y][\emptyset] & = & \textrm{true} \\
|
||||||
|
\texttt{possible}[x][y][S] & = & \texttt{possible}[x-1][y][S \setminus \texttt{value}[x][y]] \lor \\
|
||||||
|
& & \texttt{possible}[x][y-1][S \setminus \texttt{value}[x][y]] \\
|
||||||
|
\end{aligned}
|
||||||
|
\end{equation*}
|
||||||
|
The base case states that there is always a path that
|
||||||
|
does not contain any digits.
|
||||||
|
Then, in the recursive case we remove $\texttt{value}[x][y]$
|
||||||
|
from $S$, because we can collect it in square $(x,y)$.
|
||||||
|
|
||||||
|
The dynamic programming implementation is as follows:
|
||||||
|
\begin{lstlisting}
|
||||||
|
for (int x = 1; x <= n; x++) {
|
||||||
|
for (int y = 1; y <= n; y++) {
|
||||||
|
for (int b = 0; b < (1<<k); b++) {
|
||||||
|
possible[x][y][b] = possible[x-1][y][b&~value[x][y]] ||
|
||||||
|
possible[x][y-1][b&~value[x][y]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
\subsubsection{From permutations to subsets}
|
\subsubsection{From permutations to subsets}
|
||||||
|
|
||||||
Using dynamic programming, it is often possible
|
Using dynamic programming, it is often possible
|
||||||
|
|
Loading…
Reference in New Issue