Small fixes
This commit is contained in:
parent
945e52e1f7
commit
cf7bcd21c2
101
chapter10.tex
101
chapter10.tex
|
@ -369,13 +369,13 @@ do {
|
||||||
|
|
||||||
\section{Bit optimizations}
|
\section{Bit optimizations}
|
||||||
|
|
||||||
It is often possible to optimize algorithms
|
Many algorithms can be optimized using
|
||||||
using bit operations.
|
bit operations.
|
||||||
Such optimizations do not change the
|
Such optimizations do not change the
|
||||||
time complexity of the algorithm,
|
time complexity of the algorithm,
|
||||||
but they may have a large impact
|
but they may have a large impact
|
||||||
on the actual running time of the code.
|
on the actual running time of the code.
|
||||||
In this section we discuss two examples
|
In this section we discuss examples
|
||||||
of such situations.
|
of such situations.
|
||||||
|
|
||||||
\subsubsection{Hamming distances}
|
\subsubsection{Hamming distances}
|
||||||
|
@ -383,15 +383,16 @@ of such situations.
|
||||||
\index{Hamming distance}
|
\index{Hamming distance}
|
||||||
The \key{Hamming distance}
|
The \key{Hamming distance}
|
||||||
$\texttt{hamming}(a,b)$ between two
|
$\texttt{hamming}(a,b)$ between two
|
||||||
equal-length bit strings $a$ and $b$ is
|
strings $a$ and $b$ of equal length is
|
||||||
the number of positions where the strings differ.
|
the number of positions where the strings differ.
|
||||||
For example, $\texttt{hamming}(01101,11001)=2$.
|
For example,
|
||||||
|
\[\texttt{hamming}(01101,11001)=2.\]
|
||||||
|
|
||||||
Consider the following problem: Given
|
Consider the following problem: Given
|
||||||
a list of $n$ bit strings, each of length $k$,
|
a list of $n$ bit strings, each of length $k$,
|
||||||
calculate the minimum Hamming distance
|
calculate the minimum Hamming distance
|
||||||
between two strings in the list.
|
between two strings in the list.
|
||||||
For example, the answer for $[00111,01101,11110]$,
|
For example, the answer for $[00111,01101,11110]$
|
||||||
is 2, because
|
is 2, because
|
||||||
\begin{itemize}[noitemsep]
|
\begin{itemize}[noitemsep]
|
||||||
\item $\texttt{hamming}(00111,01101)=2$,
|
\item $\texttt{hamming}(00111,01101)=2$,
|
||||||
|
@ -400,11 +401,11 @@ is 2, because
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
A straightforward way to solve the problem is
|
A straightforward way to solve the problem is
|
||||||
to go through all pairs of string and calculate
|
to go through all pairs of strings and calculate
|
||||||
their Hamming distances,
|
their Hamming distances,
|
||||||
which yields an $O(n^2 k)$ time algorithm.
|
which yields an $O(n^2 k)$ time algorithm.
|
||||||
The following function calculates
|
The following function can be used to
|
||||||
the Hamming distance between two strings:
|
calculate distances:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
int hamming(string a, string b) {
|
int hamming(string a, string b) {
|
||||||
int d = 0;
|
int d = 0;
|
||||||
|
@ -445,7 +446,7 @@ Thus, the bit optimized code was almost
|
||||||
As another example, consider the
|
As another example, consider the
|
||||||
following problem:
|
following problem:
|
||||||
Given an $n \times n$ grid whose
|
Given an $n \times n$ grid whose
|
||||||
each square is either black or white,
|
each square is either black (1) or white (0),
|
||||||
calculate the number of subgrids
|
calculate the number of subgrids
|
||||||
whose all corners are black.
|
whose all corners are black.
|
||||||
For example, the grid
|
For example, the grid
|
||||||
|
@ -499,7 +500,7 @@ denotes the color in row $y$ in column $x$:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
if (color[a][i] == BLACK && color[b][i] == BLACK) count++;
|
if (color[a][i] == 1 && color[b][i] == 1) count++;
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
Then, those columns
|
Then, those columns
|
||||||
|
@ -513,7 +514,7 @@ a list of $N$-bit numbers that describe the colors
|
||||||
of the squares. Now we can process $N$ columns at the same time
|
of the squares. Now we can process $N$ columns at the same time
|
||||||
using bit operations. In the following code,
|
using bit operations. In the following code,
|
||||||
$\texttt{color}[y][k]$ represents
|
$\texttt{color}[y][k]$ represents
|
||||||
a block of $N$ colors as bits (0 is white and 1 is black).
|
a block of $N$ colors as bits.
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; i <= n/N; i++) {
|
for (int i = 0; i <= n/N; i++) {
|
||||||
|
@ -523,9 +524,9 @@ for (int i = 0; i <= n/N; i++) {
|
||||||
The resulting algorithm works in $O(n^3/N)$ time.
|
The resulting algorithm works in $O(n^3/N)$ time.
|
||||||
|
|
||||||
We generated a random grid of size $2500 \times 2500$
|
We generated a random grid of size $2500 \times 2500$
|
||||||
and compared the original and bit-optimized implementation.
|
and compared the original and bit optimized implementation.
|
||||||
While the original code took $29.6$ seconds,
|
While the original code took $29.6$ seconds,
|
||||||
the bit-optimized version only took $3.1$ seconds
|
the bit optimized version only took $3.1$ seconds
|
||||||
with $N=32$ (\texttt{int} numbers) and $1.7$ seconds
|
with $N=32$ (\texttt{int} numbers) and $1.7$ seconds
|
||||||
with $N=64$ (\texttt{long long} numbers).
|
with $N=64$ (\texttt{long long} numbers).
|
||||||
|
|
||||||
|
@ -551,10 +552,12 @@ For example, consider the following scenario ($k=3$ and $n=8$):
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\begin{tikzpicture}[scale=.65]
|
\begin{tikzpicture}[scale=.65]
|
||||||
\draw (0, 0) grid (8,3);
|
\draw (0, 0) grid (8,3);
|
||||||
\node at (-2.5,2.5) {product $A$};
|
\node at (-2.5,2.5) {product 0};
|
||||||
\node at (-2.5,1.5) {product $B$};
|
\node at (-2.5,1.5) {product 1};
|
||||||
\node at (-2.5,0.5) {product $C$};
|
\node at (-2.5,0.5) {product 2};
|
||||||
|
|
||||||
|
\foreach \x in {0,...,7}
|
||||||
|
{\node at (\x+0.5,3.5) {\x};}
|
||||||
\foreach \x/\v in {0/6,1/9,2/5,3/2,4/8,5/9,6/1,7/6}
|
\foreach \x/\v in {0/6,1/9,2/5,3/2,4/8,5/9,6/1,7/6}
|
||||||
{\node at (\x+0.5,2.5) {\v};}
|
{\node at (\x+0.5,2.5) {\v};}
|
||||||
\foreach \x/\v in {0/8,1/2,2/6,3/2,4/7,5/5,6/7,7/2}
|
\foreach \x/\v in {0/8,1/2,2/6,3/2,4/7,5/5,6/7,7/2}
|
||||||
|
@ -570,10 +573,12 @@ In this scenario, the minimum total price is $5$:
|
||||||
\fill [color=lightgray] (3, 2) rectangle (4, 3);
|
\fill [color=lightgray] (3, 2) rectangle (4, 3);
|
||||||
\fill [color=lightgray] (6, 0) rectangle (7, 1);
|
\fill [color=lightgray] (6, 0) rectangle (7, 1);
|
||||||
\draw (0, 0) grid (8,3);
|
\draw (0, 0) grid (8,3);
|
||||||
\node at (-2.5,2.5) {product $A$};
|
\node at (-2.5,2.5) {product 0};
|
||||||
\node at (-2.5,1.5) {product $B$};
|
\node at (-2.5,1.5) {product 1};
|
||||||
\node at (-2.5,0.5) {product $C$};
|
\node at (-2.5,0.5) {product 2};
|
||||||
|
|
||||||
|
\foreach \x in {0,...,7}
|
||||||
|
{\node at (\x+0.5,3.5) {\x};}
|
||||||
\foreach \x/\v in {0/6,1/9,2/5,3/2,4/8,5/9,6/1,7/6}
|
\foreach \x/\v in {0/6,1/9,2/5,3/2,4/8,5/9,6/1,7/6}
|
||||||
{\node at (\x+0.5,2.5) {\v};}
|
{\node at (\x+0.5,2.5) {\v};}
|
||||||
\foreach \x/\v in {0/8,1/2,2/6,3/2,4/7,5/5,6/7,7/2}
|
\foreach \x/\v in {0/8,1/2,2/6,3/2,4/7,5/5,6/7,7/2}
|
||||||
|
@ -584,7 +589,7 @@ In this scenario, the minimum total price is $5$:
|
||||||
\end{center}
|
\end{center}
|
||||||
|
|
||||||
Let $\texttt{price}[x][d]$ denote the price of product $x$
|
Let $\texttt{price}[x][d]$ denote the price of product $x$
|
||||||
on day $d$ where $0 \le x < k$ and $0 \le d < n$.
|
on day $d$.
|
||||||
For example, in the above scenario $\texttt{price}[2][3] = 7$.
|
For example, in the above scenario $\texttt{price}[2][3] = 7$.
|
||||||
Then, let $\texttt{total}(S,d)$ denote the minimum total
|
Then, let $\texttt{total}(S,d)$ denote the minimum total
|
||||||
price for buying a subset $S$ of products by day $d$.
|
price for buying a subset $S$ of products by day $d$.
|
||||||
|
@ -597,10 +602,10 @@ and $\texttt{total}(\{x\},0) = \texttt{price}[x][0]$,
|
||||||
because there is one way to buy one product on the first day.
|
because there is one way to buy one product on the first day.
|
||||||
Then, the following recurrence can be used:
|
Then, the following recurrence can be used:
|
||||||
\begin{equation*}
|
\begin{equation*}
|
||||||
\begin{aligned}
|
\begin{split}
|
||||||
\texttt{total}(S,d) & = \min( & \texttt{total}(S,d-1), \\
|
\texttt{total}(S,d) = \min( & \texttt{total}(S,d-1), \\
|
||||||
& & \min_{x \in S} \texttt{total}(S \setminus x,d-1)+\texttt{price}[x][d]))
|
& \min_{x \in S} (\texttt{total}(S \setminus x,d-1)+\texttt{price}[x][d]))
|
||||||
\end{aligned}
|
\end{split}
|
||||||
\end{equation*}
|
\end{equation*}
|
||||||
This means that we either do not buy any product on day $d$
|
This means that we either do not buy any product on day $d$
|
||||||
or buy a product $x$ that belongs to $S$.
|
or buy a product $x$ that belongs to $S$.
|
||||||
|
@ -667,18 +672,18 @@ and the weights are as follows:
|
||||||
\begin{tabular}{ll}
|
\begin{tabular}{ll}
|
||||||
person & weight \\
|
person & weight \\
|
||||||
\hline
|
\hline
|
||||||
$A$ & 2 \\
|
0 & 2 \\
|
||||||
$B$ & 3 \\
|
1 & 3 \\
|
||||||
$C$ & 3 \\
|
2 & 3 \\
|
||||||
$D$ & 5 \\
|
3 & 5 \\
|
||||||
$E$ & 6 \\
|
4 & 6 \\
|
||||||
\end{tabular}
|
\end{tabular}
|
||||||
\end{center}
|
\end{center}
|
||||||
In this case, the minimum number of rides is 2.
|
In this case, the minimum number of rides is 2.
|
||||||
One optimal order is $\{A,C,D,B,E\}$,
|
One optimal order is $\{0,2,3,1,4\}$,
|
||||||
which partitions the people into two rides:
|
which partitions the people into two rides:
|
||||||
first $\{A,C,D\}$ (total weight 10),
|
first $\{0,2,3\}$ (total weight 10),
|
||||||
and then $\{B,E\}$ (total weight 9).
|
and then $\{1,4\}$ (total weight 9).
|
||||||
|
|
||||||
The problem can be easily solved in $O(n! n)$ time
|
The problem can be easily solved in $O(n! n)$ time
|
||||||
by testing all possible permutations of $n$ people.
|
by testing all possible permutations of $n$ people.
|
||||||
|
@ -689,20 +694,19 @@ two values: the minimum number of rides needed and
|
||||||
the minimum weight of people who ride in the last group.
|
the minimum weight of people who ride in the last group.
|
||||||
|
|
||||||
Let $\texttt{weight}[p]$ denote the weight of
|
Let $\texttt{weight}[p]$ denote the weight of
|
||||||
person $p$ where $0 \le p < n$.
|
person $p$.
|
||||||
Then we define two functions:
|
We define two functions:
|
||||||
$\texttt{rides}(S)$ is the minimum number of
|
$\texttt{rides}(S)$ is the minimum number of
|
||||||
rides for a subset $S$,
|
rides for a subset $S$,
|
||||||
and $\texttt{last}(S)$ is the minimum weight
|
and $\texttt{last}(S)$ is the minimum weight
|
||||||
of the last ride.
|
of the last ride.
|
||||||
For example, in the above scenario
|
For example, in the above scenario
|
||||||
\[ \texttt{rides}(\{B,D,E\})=2 \hspace{10px} \textrm{and}
|
\[ \texttt{rides}(\{1,3,4\})=2 \hspace{10px} \textrm{and}
|
||||||
\hspace{10px} \texttt{last}(\{B,D,E\})=5,\]
|
\hspace{10px} \texttt{last}(\{1,3,4\})=5,\]
|
||||||
because the optimal rides are $\{B,E\}$ and $\{D\}$,
|
because the optimal rides are $\{1,4\}$ and $\{3\}$,
|
||||||
and the second ride has weight 5.
|
and the second ride has weight 5.
|
||||||
Of course, our final goal is to calculate the value
|
Of course, our final goal is to calculate the value
|
||||||
of $\texttt{rides}(P)$ where $P$ is a set that
|
of $\texttt{rides}(\{0 \ldots n-1\})$.
|
||||||
contains all the people.
|
|
||||||
|
|
||||||
We can calculate the values
|
We can calculate the values
|
||||||
of the functions recursively and then apply
|
of the functions recursively and then apply
|
||||||
|
@ -717,13 +721,14 @@ we can add $p$ to the last ride.
|
||||||
Otherwise, we have to reserve a new ride
|
Otherwise, we have to reserve a new ride
|
||||||
that initially only contains $p$.
|
that initially only contains $p$.
|
||||||
|
|
||||||
A convenient way to implement a dynamic programming
|
To implement dynamic programming,
|
||||||
solution is to declare an array
|
we declare an array
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
pair<int,int> best[1<<N];
|
pair<int,int> best[1<<N];
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
that contains values of \texttt{rides} and \texttt{weight}
|
that contains for each subset $S$
|
||||||
as pairs. For an empty group, no rides are needed:
|
a pair $(\texttt{rides}(S),\texttt{last}(S)$.
|
||||||
|
For an empty group, no rides are needed:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
best[0] = {0,0};
|
best[0] = {0,0};
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
@ -731,13 +736,16 @@ Then, we can fill the array as follows:
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
for (int s = 1; s < (1<<n); s++) {
|
for (int s = 1; s < (1<<n); s++) {
|
||||||
|
// initial value: n rides are needed
|
||||||
best[s] = {n,0};
|
best[s] = {n,0};
|
||||||
for (int p = 0; p < n; p++) {
|
for (int p = 0; p < n; p++) {
|
||||||
if (s&(1<<p)) {
|
if (s&(1<<p)) {
|
||||||
auto option = best[s^(1<<p)];
|
auto option = best[s^(1<<p)];
|
||||||
if (option.second+weight[p] <= x) {
|
if (option.second+weight[p] <= x) {
|
||||||
|
// add p to an existing ride
|
||||||
option.second += weight[p];
|
option.second += weight[p];
|
||||||
} else {
|
} else {
|
||||||
|
// reserve a new ride for p
|
||||||
option.first++;
|
option.first++;
|
||||||
option.second = weight[p];
|
option.second = weight[p];
|
||||||
}
|
}
|
||||||
|
@ -746,7 +754,8 @@ for (int s = 1; s < (1<<n); s++) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
Note that in the above loop, for any two subsets $S_1$ and $S_2$
|
Note that the above loop guarantees that
|
||||||
|
for any two subsets $S_1$ and $S_2$
|
||||||
such that $S_1 \subset S_2$, we process $S_1$ before $S_2$.
|
such that $S_1 \subset S_2$, we process $S_1$ before $S_2$.
|
||||||
Thus, the dynamic programming values are calculated in the
|
Thus, the dynamic programming values are calculated in the
|
||||||
correct order.
|
correct order.
|
||||||
|
@ -787,7 +796,7 @@ pairs of subsets in $O(2^{2n})$ time.
|
||||||
However, using dynamic programming, we
|
However, using dynamic programming, we
|
||||||
can solve the problem in $O(2^n n)$ time.
|
can solve the problem in $O(2^n n)$ time.
|
||||||
The idea is to focus on sums where the
|
The idea is to focus on sums where the
|
||||||
elements that may removed from $S$ are restricted.
|
elements that may be removed from $S$ are restricted.
|
||||||
|
|
||||||
Let $\texttt{partial}(S,k)$ denote the sum of
|
Let $\texttt{partial}(S,k)$ denote the sum of
|
||||||
values of subsets of $S$ with the restriction
|
values of subsets of $S$ with the restriction
|
||||||
|
|
Loading…
Reference in New Issue