Start revision for Chapter 10
This commit is contained in:
parent
758ed890ce
commit
04f3c313cc
186
chapter10.tex
186
chapter10.tex
|
@ -330,7 +330,7 @@ difference & $a \setminus b$ & $a$ \& (\textasciitilde$b$) \\
|
||||||
|
|
||||||
For example, the following code first constructs
|
For example, the following code first constructs
|
||||||
the sets $x=\{1,3,4,8\}$ and $y=\{3,6,8,9\}$,
|
the sets $x=\{1,3,4,8\}$ and $y=\{3,6,8,9\}$,
|
||||||
and then calculates the set $z = x \cup y = \{1,3,4,6,8,9\}$:
|
and then constructs the set $z = x \cup y = \{1,3,4,6,8,9\}$:
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
int x = (1<<1)+(1<<3)+(1<<4)+(1<<8);
|
int x = (1<<1)+(1<<3)+(1<<4)+(1<<8);
|
||||||
|
@ -367,6 +367,76 @@ do {
|
||||||
} while (b=(b-x)&x);
|
} while (b=(b-x)&x);
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\section{Bit optimizations}
|
||||||
|
|
||||||
|
It is often possible to optimize algorithms
|
||||||
|
using bit operations.
|
||||||
|
Such optimizations do not change the
|
||||||
|
time complexity of the algorithm,
|
||||||
|
but they may have a large impact
|
||||||
|
on the actual running time of the code.
|
||||||
|
In this section we discuss examples
|
||||||
|
of such situations.
|
||||||
|
|
||||||
|
\subsubsection{Hamming distances}
|
||||||
|
|
||||||
|
\index{Hamming distance}
|
||||||
|
The \key{Hamming distance} between two bit strings
|
||||||
|
of equal length is
|
||||||
|
the number of positions where the strings differ.
|
||||||
|
For example, the Hamming distance between
|
||||||
|
01101 and 11001 is 2.
|
||||||
|
|
||||||
|
Consider the following problem: We are given
|
||||||
|
a list of $n$ bit strings, each of length $k$,
|
||||||
|
and our task is to calculate the minimum Hamming distance
|
||||||
|
between two strings in the list.
|
||||||
|
For example, the minimum distance for the list
|
||||||
|
$[00111,01101,11101]$ is 2.
|
||||||
|
|
||||||
|
A straightforward way to solve the problem is
|
||||||
|
to go through all pairs of string and calculate
|
||||||
|
their Hamming distances.
|
||||||
|
Such an algorithm works in $O(n^2 k)$ time.
|
||||||
|
The following function can be used to calculate
|
||||||
|
the Hamming distance between two strings:
|
||||||
|
\begin{lstlisting}
|
||||||
|
int distance(string a, string b) {
|
||||||
|
int d = 0;
|
||||||
|
for (int i = 0; i < k; i++) {
|
||||||
|
if (a[i] != b[i]) d++;
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
However, if $k$ is small, we can optimize the code
|
||||||
|
by storing the bit strings as integers and
|
||||||
|
calculating the Hamming distances using bit operations.
|
||||||
|
In particular, if $k \le 32$, we can just store
|
||||||
|
the strings as \texttt{int} values and use the
|
||||||
|
following function to calculate distances:
|
||||||
|
\begin{lstlisting}
|
||||||
|
int distance(int a, int b) {
|
||||||
|
return __builtin_popcount(a^b);
|
||||||
|
}
|
||||||
|
\end{lstlisting}
|
||||||
|
In the above function, the xor operation constructs
|
||||||
|
a bit string that has one bits in positions
|
||||||
|
where $a$ and $b$ differ.
|
||||||
|
Then, the number of bits is calculated using
|
||||||
|
the \texttt{\_\_builtin\_popcount} function.
|
||||||
|
|
||||||
|
To compare the implementations, we generated
|
||||||
|
a list of 10000 random bit strings of length 30.
|
||||||
|
Using the first approach, the search took
|
||||||
|
13.5 seconds, and after the bit optimization,
|
||||||
|
it took only 0.5 seconds.
|
||||||
|
Thus, the bit optimized code was almost
|
||||||
|
30 times faster than the original code.
|
||||||
|
|
||||||
|
\subsubsection{}
|
||||||
|
|
||||||
\section{Dynamic programming}
|
\section{Dynamic programming}
|
||||||
|
|
||||||
\subsubsection{From permutations to subsets}
|
\subsubsection{From permutations to subsets}
|
||||||
|
@ -379,7 +449,7 @@ contains a subset of a set and possibly
|
||||||
some additional information\footnote{This technique was introduced in 1962
|
some additional information\footnote{This technique was introduced in 1962
|
||||||
by M. Held and R. M. Karp \cite{hel62}.}.
|
by M. Held and R. M. Karp \cite{hel62}.}.
|
||||||
|
|
||||||
The benefit in this is that
|
The benefit of this is that
|
||||||
$n!$, the number of permutations of an $n$ element set,
|
$n!$, the number of permutations of an $n$ element set,
|
||||||
is much larger than $2^n$, the number of subsets
|
is much larger than $2^n$, the number of subsets
|
||||||
of the same set.
|
of the same set.
|
||||||
|
@ -388,68 +458,64 @@ $n! \approx 2.4 \cdot 10^{18}$ and $2^n \approx 10^6$.
|
||||||
Hence, for certain values of $n$,
|
Hence, for certain values of $n$,
|
||||||
we can efficiently go through subsets but not through permutations.
|
we can efficiently go through subsets but not through permutations.
|
||||||
|
|
||||||
As an example, consider the problem of
|
As an example, consider the following problem:
|
||||||
calculating the number of
|
There is an elevator with maximum weight $x$,
|
||||||
permutations of a set $\{0,1,\ldots,n-1\}$,
|
and $n$ people with known weights
|
||||||
where the difference between any two consecutive
|
who want to get from the ground floor
|
||||||
elements is larger than one.
|
to the top floor.
|
||||||
For example, when $n=4$, there are two such permutations:
|
What is the minimum number of rides needed
|
||||||
$(1,3,0,2)$ and $(2,0,3,1)$.
|
if the people enter the elevator in an optimal order?
|
||||||
|
|
||||||
Let $f(x,k)$ denote the number of valid permutations
|
For example, suppose that $x=10$, $n=5$
|
||||||
of a subset $x$ where the last element is $k$ and
|
and the weights are as follows:
|
||||||
the difference between any two consecutive
|
\begin{center}
|
||||||
elements is larger than one.
|
\begin{tabular}{ll}
|
||||||
For example, $f(\{0,1,3\},1)=1$,
|
person & weight \\
|
||||||
because there is a permutation $(0,3,1)$,
|
\hline
|
||||||
and $f(\{0,1,3\},3)=0$, because 0 and 1
|
$A$ & 2 \\
|
||||||
cannot be next to each other.
|
$B$ & 3 \\
|
||||||
|
$C$ & 3 \\
|
||||||
|
$D$ & 5 \\
|
||||||
|
$E$ & 6 \\
|
||||||
|
\end{tabular}
|
||||||
|
\end{center}
|
||||||
|
In this case, the minimum number of rides is 2.
|
||||||
|
One optimal order is $\{A,C,D,B,E\}$,
|
||||||
|
which partitions the people into two rides:
|
||||||
|
first $\{A,C,D\}$ (total weight 10),
|
||||||
|
and then $\{B,E\}$ (total weight 9).
|
||||||
|
|
||||||
Using $f$, the answer to the problem equals
|
The problem can be easily solved in $O(n! n)$ time
|
||||||
\[ \sum_{i=0}^{n-1} f(\{0,1,\ldots,n-1\},i), \]
|
by testing all possible permutations of $n$ people.
|
||||||
because the permutation has to contain all
|
However, we can use dynamic programming to get
|
||||||
elements $\{0,1,\ldots,n-1\}$ and the last
|
a more efficient $O(2^n n)$ time algorithm.
|
||||||
element can be any element.
|
The idea is to calculate for each subset of people
|
||||||
|
two values: the minimum number of rides needed and
|
||||||
|
the minimum weight of people who ride in the last group.
|
||||||
|
|
||||||
The dynamic programming values can be stored as follows:
|
Let $\texttt{rides}(X)$ denote the minimum number
|
||||||
\begin{lstlisting}
|
of rides and $\texttt{weight}(X)$ denote the minimum
|
||||||
int d[1<<n][n];
|
weight of the last group, where $X$ is a subset
|
||||||
\end{lstlisting}
|
of people. For example,
|
||||||
|
\[ \texttt{rides}(\{B,D,E\})=2 \hspace{10px} \textrm{and}
|
||||||
|
\hspace{10px} \texttt{weight}(\{B,D,E\})=5,\]
|
||||||
|
because the optimal rides are $\{B,E\}$ and $\{D\}$,
|
||||||
|
and the second ride has weight 5.
|
||||||
|
Of course, our final goal is to calculate the value
|
||||||
|
of $\texttt{rides}(\{A,B,C,D,E\})$ that is the solution
|
||||||
|
to the problem.
|
||||||
|
|
||||||
First, $f(\{k\},k)=1$ for all values of $k$:
|
It turns out that we can calculate the values
|
||||||
\begin{lstlisting}
|
of the functions recursively and then apply
|
||||||
for (int i = 0; i < n; i++) d[1<<i][i] = 1;
|
dynamic programming.
|
||||||
\end{lstlisting}
|
The idea is to go through all people
|
||||||
|
that belong to $X$ and optimally
|
||||||
Then, the other values can be calculated
|
choose the last person who enters the elevator.
|
||||||
as follows:
|
For example, if $X=\{B,D,E\}$,
|
||||||
\begin{lstlisting}
|
one of $B$, $D$ and $E$ is the last person
|
||||||
for (int b = 0; b < (1<<n); b++) {
|
who enters the elevator.
|
||||||
for (int i = 0; i < n; i++) {
|
Each such choice yields a subproblem
|
||||||
for (int j = 0; j < n; j++) {
|
for a smaller subset of people.
|
||||||
if (abs(i-j) > 1 && (b&(1<<i)) && (b&(1<<j))) {
|
|
||||||
d[b][i] += d[b^(1<<i)][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
\end{lstlisting}
|
|
||||||
|
|
||||||
In the above code,
|
|
||||||
the variable $b$ goes through all subsets and each
|
|
||||||
permutation is of the form $(\ldots,j,i)$,
|
|
||||||
where the difference between $i$ and $j$ is
|
|
||||||
larger than one and $i$ and $j$ belong to $b$.
|
|
||||||
|
|
||||||
Finally, the number of solutions can be
|
|
||||||
calculated as follows:
|
|
||||||
|
|
||||||
\begin{lstlisting}
|
|
||||||
int s = 0;
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
s += d[(1<<n)-1][i];
|
|
||||||
}
|
|
||||||
\end{lstlisting}
|
|
||||||
|
|
||||||
\subsubsection{Counting subsets}
|
\subsubsection{Counting subsets}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue