2016-12-28 23:54:51 +01:00
|
|
|
\chapter{Bit manipulation}
|
|
|
|
|
2017-02-16 22:31:26 +01:00
|
|
|
All data in computer programs is internally stored as bits,
|
2017-02-04 21:10:45 +01:00
|
|
|
i.e., as numbers 0 and 1.
|
2017-05-21 14:37:52 +02:00
|
|
|
This chapter discusses the bit representation
|
|
|
|
of integers, and shows examples
|
|
|
|
of how to use bit operations.
|
2017-01-07 12:34:28 +01:00
|
|
|
It turns out that there are many uses for
|
2017-05-21 14:37:52 +02:00
|
|
|
bit manipulation in algorithm programming.
|
2017-01-07 12:34:28 +01:00
|
|
|
|
|
|
|
\section{Bit representation}
|
|
|
|
|
|
|
|
\index{bit representation}
|
|
|
|
|
2017-05-21 14:37:52 +02:00
|
|
|
In programming, an $n$ bit integer is internally
|
|
|
|
stored as a binary number that consists of $n$ bits.
|
|
|
|
For example, the C++ type \texttt{int} is
|
|
|
|
a 32-bit type, which means that every \texttt{int}
|
|
|
|
number consists of 32 bits.
|
|
|
|
|
|
|
|
Here is the bit representation of
|
|
|
|
the \texttt{int} number 43:
|
2016-12-28 23:54:51 +01:00
|
|
|
\[00000000000000000000000000101011\]
|
2017-05-21 14:37:52 +02:00
|
|
|
The bits in the representation are indexed from right to left.
|
|
|
|
To convert a bit representation $b_k \cdots b_2 b_1 b_0$ into a number,
|
|
|
|
we can use the formula
|
|
|
|
\[b_k 2^k + \ldots + b_2 2^2 + b_1 2^1 + b_0 2^0.\]
|
|
|
|
For example,
|
|
|
|
\[1 \cdot 2^5 + 1 \cdot 2^3 + 1 \cdot 2^1 + 1 \cdot 2^0 = 43.\]
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
The bit representation of a number is either
|
|
|
|
\key{signed} or \key{unsigned}.
|
2017-02-04 21:10:45 +01:00
|
|
|
Usually a signed representation is used,
|
|
|
|
which means that both negative and positive
|
|
|
|
numbers can be represented.
|
2017-05-21 14:37:52 +02:00
|
|
|
A signed variable of $n$ bits can contain any
|
2017-03-01 21:03:44 +01:00
|
|
|
integer between $-2^{n-1}$ and $2^{n-1}-1$.
|
2017-02-04 21:10:45 +01:00
|
|
|
For example, the \texttt{int} type in C++ is
|
2017-05-21 14:37:52 +02:00
|
|
|
a signed type, so an \texttt{int} variable can contain any
|
2017-03-01 21:03:44 +01:00
|
|
|
integer between $-2^{31}$ and $2^{31}-1$.
|
2017-02-04 21:10:45 +01:00
|
|
|
|
|
|
|
The first bit in a signed representation
|
|
|
|
is the sign of the number (0 for nonnegative numbers
|
|
|
|
and 1 for negative numbers), and
|
2017-02-16 22:31:26 +01:00
|
|
|
the remaining $n-1$ bits contain the magnitude of the number.
|
2017-02-04 21:10:45 +01:00
|
|
|
\key{Two's complement} is used, which means that the
|
|
|
|
opposite number of a number is calculated by first
|
|
|
|
inverting all the bits in the number,
|
2017-01-07 12:34:28 +01:00
|
|
|
and then increasing the number by one.
|
|
|
|
|
2017-05-21 14:37:52 +02:00
|
|
|
For example, the bit representation of
|
|
|
|
the \texttt{int} number $-43$ is
|
|
|
|
\[11111111111111111111111111010101.\]
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-28 19:00:15 +01:00
|
|
|
In an unsigned representation, only nonnegative
|
2017-05-21 14:37:52 +02:00
|
|
|
numbers can be used, but the upper bound for the values is larger.
|
|
|
|
An unsigned variable of $n$ bits can contain any
|
2017-02-04 21:10:45 +01:00
|
|
|
integer between $0$ and $2^n-1$.
|
2017-05-21 14:37:52 +02:00
|
|
|
For example, in C++, an \texttt{unsigned int} variable
|
2017-02-04 21:10:45 +01:00
|
|
|
can contain any integer between $0$ and $2^{32}-1$.
|
|
|
|
|
2017-05-21 14:37:52 +02:00
|
|
|
There is a connection between the
|
2017-02-04 21:10:45 +01:00
|
|
|
representations:
|
2017-05-21 14:37:52 +02:00
|
|
|
a signed number $-x$ equals an unsigned number $2^n-x$.
|
2017-02-04 21:10:45 +01:00
|
|
|
For example, the following code shows that
|
|
|
|
the signed number $x=-43$ equals the unsigned
|
|
|
|
number $y=2^{32}-43$:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
int x = -43;
|
|
|
|
unsigned int y = x;
|
|
|
|
cout << x << "\n"; // -43
|
|
|
|
cout << y << "\n"; // 4294967253
|
|
|
|
\end{lstlisting}
|
2017-01-07 12:34:28 +01:00
|
|
|
|
2017-02-04 21:10:45 +01:00
|
|
|
If a number is larger than the upper bound
|
|
|
|
of the bit representation, the number will overflow.
|
|
|
|
In a signed representation,
|
2017-01-07 12:34:28 +01:00
|
|
|
the next number after $2^{n-1}-1$ is $-2^{n-1}$,
|
|
|
|
and in an unsigned representation,
|
|
|
|
the next number after $2^{n-1}$ is $0$.
|
2017-02-16 22:31:26 +01:00
|
|
|
For example, consider the following code:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
int x = 2147483647
|
|
|
|
cout << x << "\n"; // 2147483647
|
|
|
|
x++;
|
|
|
|
cout << x << "\n"; // -2147483648
|
|
|
|
\end{lstlisting}
|
|
|
|
|
2017-02-16 22:31:26 +01:00
|
|
|
Initially, the value of $x$ is $2^{31}-1$.
|
2017-05-21 14:37:52 +02:00
|
|
|
This is the largest value that can be stored
|
2017-02-16 22:31:26 +01:00
|
|
|
in an \texttt{int} variable,
|
|
|
|
so the next number after $2^{31}-1$ is $-2^{31}$.
|
|
|
|
|
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
\section{Bit operations}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\newcommand\XOR{\mathbin{\char`\^}}
|
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
\subsubsection{And operation}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
\index{and operation}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
The \key{and} operation $x$ \& $y$ produces a number
|
2017-02-04 21:10:45 +01:00
|
|
|
that has one bits in positions where both
|
|
|
|
$x$ and $y$ have one bits.
|
|
|
|
For example, $22$ \& $26$ = 18, because
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{center}
|
|
|
|
\begin{tabular}{rrr}
|
|
|
|
& 10110 & (22)\\
|
|
|
|
\& & 11010 & (26) \\
|
|
|
|
\hline
|
|
|
|
= & 10010 & (18) \\
|
|
|
|
\end{tabular}
|
|
|
|
\end{center}
|
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
Using the and operation, we can check if a number
|
|
|
|
$x$ is even because
|
|
|
|
$x$ \& $1$ = 0 if $x$ is even, and
|
|
|
|
$x$ \& $1$ = 1 if $x$ is odd.
|
2017-02-04 21:10:45 +01:00
|
|
|
More generally, $x$ is divisible by $2^k$
|
|
|
|
exactly when $x$ \& $(2^k-1)$ = 0.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
\subsubsection{Or operation}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
\index{or operation}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
The \key{or} operation $x$ | $y$ produces a number
|
2017-02-04 21:10:45 +01:00
|
|
|
that has one bits in positions where at least one
|
|
|
|
of $x$ and $y$ have one bits.
|
|
|
|
For example, $22$ | $26$ = 30, because
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{center}
|
|
|
|
\begin{tabular}{rrr}
|
|
|
|
& 10110 & (22)\\
|
|
|
|
| & 11010 & (26) \\
|
|
|
|
\hline
|
|
|
|
= & 11110 & (30) \\
|
|
|
|
\end{tabular}
|
|
|
|
\end{center}
|
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
\subsubsection{Xor operation}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
\index{xor operation}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
The \key{xor} operation $x$ $\XOR$ $y$ produces a number
|
2017-02-04 21:10:45 +01:00
|
|
|
that has one bits in positions where exactly one
|
|
|
|
of $x$ and $y$ have one bits.
|
|
|
|
For example, $22$ $\XOR$ $26$ = 12, because
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{center}
|
|
|
|
\begin{tabular}{rrr}
|
|
|
|
& 10110 & (22)\\
|
|
|
|
$\XOR$ & 11010 & (26) \\
|
|
|
|
\hline
|
|
|
|
= & 01100 & (12) \\
|
|
|
|
\end{tabular}
|
|
|
|
\end{center}
|
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
\subsubsection{Not operation}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
\index{not operation}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
The \key{not} operation \textasciitilde$x$
|
|
|
|
produces a number where all the bits of $x$
|
2017-02-04 21:10:45 +01:00
|
|
|
have been inverted.
|
2017-01-07 12:34:28 +01:00
|
|
|
The formula \textasciitilde$x = -x-1$ holds,
|
|
|
|
for example, \textasciitilde$29 = -30$.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
The result of the not operation at the bit level
|
2017-02-04 21:10:45 +01:00
|
|
|
depends on the length of the bit representation,
|
2017-05-21 14:37:52 +02:00
|
|
|
because the operation inverts all bits.
|
2017-01-07 12:34:28 +01:00
|
|
|
For example, if the numbers are 32-bit
|
|
|
|
\texttt{int} numbers, the result is as follows:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{center}
|
|
|
|
\begin{tabular}{rrrr}
|
|
|
|
$x$ & = & 29 & 00000000000000000000000000011101 \\
|
|
|
|
\textasciitilde$x$ & = & $-30$ & 11111111111111111111111111100010 \\
|
|
|
|
\end{tabular}
|
|
|
|
\end{center}
|
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
\subsubsection{Bit shifts}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 12:34:28 +01:00
|
|
|
\index{bit shift}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-04 21:10:45 +01:00
|
|
|
The left bit shift $x < < k$ appends $k$
|
2017-02-16 22:31:26 +01:00
|
|
|
zero bits to the number,
|
2017-01-07 12:34:28 +01:00
|
|
|
and the right bit shift $x > > k$
|
2017-02-04 21:10:45 +01:00
|
|
|
removes the $k$ last bits from the number.
|
|
|
|
For example, $14 < < 2 = 56$,
|
2017-05-21 14:37:52 +02:00
|
|
|
because $14$ and $56$ correspond to 1110 and 111000.
|
2017-02-11 20:39:03 +01:00
|
|
|
Similarly, $49 > > 3 = 6$,
|
2017-05-21 14:37:52 +02:00
|
|
|
because $49$ and $6$ correspond to 110001 and 110.
|
2017-02-04 21:10:45 +01:00
|
|
|
|
|
|
|
Note that $x < < k$
|
|
|
|
corresponds to multiplying $x$ by $2^k$,
|
|
|
|
and $x > > k$
|
2017-01-07 12:34:28 +01:00
|
|
|
corresponds to dividing $x$ by $2^k$
|
2017-02-04 21:10:45 +01:00
|
|
|
rounded down to an integer.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-04 21:10:45 +01:00
|
|
|
\subsubsection{Applications}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-04 21:10:45 +01:00
|
|
|
A number of the form $1 < < k$ has a one bit
|
2017-02-16 22:31:26 +01:00
|
|
|
in position $k$ and all other bits are zero,
|
2017-02-04 21:10:45 +01:00
|
|
|
so we can use such numbers to access single bits of numbers.
|
2017-05-21 14:37:52 +02:00
|
|
|
In particular, the $k$th bit of a number is one
|
2017-02-04 21:10:45 +01:00
|
|
|
exactly when $x$ \& $(1 < < k)$ is not zero.
|
|
|
|
The following code prints the bit representation
|
|
|
|
of an \texttt{int} number $x$:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-04 21:10:45 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
for (int i = 31; i >= 0; i--) {
|
|
|
|
if (x&(1<<i)) cout << "1";
|
|
|
|
else cout << "0";
|
|
|
|
}
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
|
|
It is also possible to modify single bits
|
2017-05-21 14:37:52 +02:00
|
|
|
of numbers using similar ideas.
|
|
|
|
For example, the formula $x$ | $(1 < < k)$
|
2017-01-07 12:34:28 +01:00
|
|
|
sets the $k$th bit of $x$ to one,
|
2017-05-21 14:37:52 +02:00
|
|
|
the formula
|
2016-12-28 23:54:51 +01:00
|
|
|
$x$ \& \textasciitilde $(1 < < k)$
|
2017-01-07 12:34:28 +01:00
|
|
|
sets the $k$th bit of $x$ to zero,
|
2017-05-21 14:37:52 +02:00
|
|
|
and the formula
|
2017-01-07 12:34:28 +01:00
|
|
|
$x$ $\XOR$ $(1 < < k)$
|
2017-02-04 21:10:45 +01:00
|
|
|
inverts the $k$th bit of $x$.
|
2017-01-07 12:34:28 +01:00
|
|
|
|
|
|
|
The formula $x$ \& $(x-1)$ sets the last
|
|
|
|
one bit of $x$ to zero,
|
|
|
|
and the formula $x$ \& $-x$ sets all the
|
|
|
|
one bits to zero, except for the last one bit.
|
2017-02-04 21:10:45 +01:00
|
|
|
The formula $x$ | $(x-1)$
|
|
|
|
inverts all the bits after the last one bit.
|
2017-01-07 12:34:28 +01:00
|
|
|
Also note that a positive number $x$ is
|
2017-05-21 14:37:52 +02:00
|
|
|
a power of two exactly when $x$ \& $(x-1) = 0$.
|
2017-01-07 12:34:28 +01:00
|
|
|
|
|
|
|
\subsubsection*{Additional functions}
|
|
|
|
|
2017-02-04 21:10:45 +01:00
|
|
|
The g++ compiler provides the following
|
|
|
|
functions for counting bits:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{itemize}
|
|
|
|
\item
|
|
|
|
$\texttt{\_\_builtin\_clz}(x)$:
|
2017-01-07 12:34:28 +01:00
|
|
|
the number of zeros at the beginning of the number
|
2016-12-28 23:54:51 +01:00
|
|
|
\item
|
|
|
|
$\texttt{\_\_builtin\_ctz}(x)$:
|
2017-01-07 12:34:28 +01:00
|
|
|
the number of zeros at the end of the number
|
2016-12-28 23:54:51 +01:00
|
|
|
\item
|
|
|
|
$\texttt{\_\_builtin\_popcount}(x)$:
|
2017-01-07 12:34:28 +01:00
|
|
|
the number of ones in the number
|
2016-12-28 23:54:51 +01:00
|
|
|
\item
|
|
|
|
$\texttt{\_\_builtin\_parity}(x)$:
|
2017-01-07 12:34:28 +01:00
|
|
|
the parity (even or odd) of the number of ones
|
2016-12-28 23:54:51 +01:00
|
|
|
\end{itemize}
|
|
|
|
\begin{samepage}
|
|
|
|
|
2017-02-04 21:10:45 +01:00
|
|
|
The functions can be used as follows:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
int x = 5328; // 00000000000000000001010011010000
|
|
|
|
cout << __builtin_clz(x) << "\n"; // 19
|
|
|
|
cout << __builtin_ctz(x) << "\n"; // 4
|
|
|
|
cout << __builtin_popcount(x) << "\n"; // 5
|
|
|
|
cout << __builtin_parity(x) << "\n"; // 1
|
|
|
|
\end{lstlisting}
|
|
|
|
\end{samepage}
|
|
|
|
|
2017-05-21 14:37:52 +02:00
|
|
|
While the above functions only support \texttt{int} numbers,
|
|
|
|
there are also \texttt{long long} versions of
|
|
|
|
the functions available with the suffix \texttt{ll}.
|
2017-01-07 12:34:28 +01:00
|
|
|
|
2017-02-04 21:10:45 +01:00
|
|
|
\section{Representing sets}
|
2017-01-07 12:34:28 +01:00
|
|
|
|
2017-05-21 14:37:52 +02:00
|
|
|
Every subset of a set
|
|
|
|
$\{0,1,2,\ldots,n-1\}$
|
|
|
|
can be represented as an $n$ bit integer
|
|
|
|
whose one bits indicate which
|
|
|
|
elements belong to the subset.
|
|
|
|
This is an efficient way to represent sets,
|
|
|
|
because every element requires only one bit of memory,
|
|
|
|
and set operations can be implemented as bit operations.
|
|
|
|
|
|
|
|
For example, since \texttt{int} is a 32-bit type,
|
|
|
|
an \texttt{int} number can represent any subset
|
|
|
|
of the set $\{0,1,2,\ldots,31\}$.
|
|
|
|
The bit representation of the set $\{1,3,4,8\}$ is
|
|
|
|
\[00000000000000000000000100011010,\]
|
|
|
|
which corresponds to the number $2^8+2^4+2^3+2^1=282$.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-16 22:31:26 +01:00
|
|
|
\subsubsection{Set implementation}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-05-21 14:37:52 +02:00
|
|
|
The following code declares an \texttt{int}
|
|
|
|
variable $x$ that can contain
|
|
|
|
a subset of $\{0,1,2,\ldots,31\}$.
|
|
|
|
After this, the code adds the elements 1, 3, 4 and 8
|
|
|
|
to the set and prints the size of the set.
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
int x = 0;
|
|
|
|
x |= (1<<1);
|
|
|
|
x |= (1<<3);
|
|
|
|
x |= (1<<4);
|
|
|
|
x |= (1<<8);
|
2017-05-21 14:37:52 +02:00
|
|
|
cout << __builtin_popcount(x) << "\n"; // 4
|
|
|
|
\end{lstlisting}
|
|
|
|
Then, the following code prints all
|
|
|
|
elements that belong to the set:
|
|
|
|
\begin{lstlisting}
|
2016-12-28 23:54:51 +01:00
|
|
|
for (int i = 0; i < 32; i++) {
|
|
|
|
if (x&(1<<i)) cout << i << " ";
|
|
|
|
}
|
2017-05-21 14:37:52 +02:00
|
|
|
// output: 1 3 4 8
|
2017-02-16 22:31:26 +01:00
|
|
|
\end{lstlisting}
|
|
|
|
|
|
|
|
\subsubsection{Set operations}
|
|
|
|
|
2017-05-21 14:37:52 +02:00
|
|
|
Set operations can be implemented as follows as bit operations:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-05-21 14:37:52 +02:00
|
|
|
\begin{center}
|
|
|
|
\begin{tabular}{lll}
|
|
|
|
& set syntax & bit syntax \\
|
|
|
|
\hline
|
|
|
|
intersection & $a \cap b$ & $a$ \& $b$ \\
|
|
|
|
union & $a \cup b$ & $a$ | $b$ \\
|
|
|
|
complement & $\bar a$ & \textasciitilde$a$ \\
|
|
|
|
difference & $a \setminus b$ & $a$ \& (\textasciitilde$b$) \\
|
|
|
|
\end{tabular}
|
|
|
|
\end{center}
|
|
|
|
|
|
|
|
For example, the following code first constructs
|
|
|
|
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\}$:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{lstlisting}
|
|
|
|
int x = (1<<1)+(1<<3)+(1<<4)+(1<<8);
|
|
|
|
int y = (1<<3)+(1<<6)+(1<<8)+(1<<9);
|
|
|
|
int z = x|y;
|
2017-05-21 14:37:52 +02:00
|
|
|
cout << __builtin_popcount(z) << "\n"; // 6
|
2017-02-16 22:31:26 +01:00
|
|
|
\end{lstlisting}
|
|
|
|
|
2017-01-07 12:51:53 +01:00
|
|
|
\subsubsection{Iterating through subsets}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-04 21:47:12 +01:00
|
|
|
The following code goes through
|
2017-01-07 12:51:53 +01:00
|
|
|
the subsets of $\{0,1,\ldots,n-1\}$:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{lstlisting}
|
|
|
|
for (int b = 0; b < (1<<n); b++) {
|
2017-01-07 12:51:53 +01:00
|
|
|
// process subset b
|
2016-12-28 23:54:51 +01:00
|
|
|
}
|
|
|
|
\end{lstlisting}
|
2017-01-07 12:51:53 +01:00
|
|
|
The following code goes through
|
2017-02-04 21:47:12 +01:00
|
|
|
the subsets with exactly $k$ elements:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
for (int b = 0; b < (1<<n); b++) {
|
|
|
|
if (__builtin_popcount(b) == k) {
|
2017-01-07 12:51:53 +01:00
|
|
|
// process subset b
|
2016-12-28 23:54:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
\end{lstlisting}
|
2017-01-07 12:51:53 +01:00
|
|
|
The following code goes through the subsets
|
|
|
|
of a set $x$:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
int b = 0;
|
|
|
|
do {
|
2017-01-07 12:51:53 +01:00
|
|
|
// process subset b
|
2016-12-28 23:54:51 +01:00
|
|
|
} while (b=(b-x)&x);
|
|
|
|
\end{lstlisting}
|
|
|
|
|
2017-01-07 14:35:53 +01:00
|
|
|
\section{Dynamic programming}
|
|
|
|
|
|
|
|
\subsubsection{From permutations to subsets}
|
|
|
|
|
|
|
|
Using dynamic programming, it is often possible
|
2017-02-16 22:31:26 +01:00
|
|
|
to change an iteration over permutations into
|
|
|
|
an iteration over subsets, so that
|
2017-02-04 21:47:12 +01:00
|
|
|
the dynamic programming state
|
2017-01-07 14:35:53 +01:00
|
|
|
contains a subset of a set and possibly
|
2017-02-25 16:57:10 +01:00
|
|
|
some additional information\footnote{This technique was introduced in 1962
|
|
|
|
by M. Held and R. M. Karp \cite{hel62}.}.
|
2017-01-07 14:35:53 +01:00
|
|
|
|
2017-02-04 21:47:12 +01:00
|
|
|
The benefit in this is that
|
2017-01-07 14:35:53 +01:00
|
|
|
$n!$, the number of permutations of an $n$ element set,
|
2017-02-16 22:31:26 +01:00
|
|
|
is much larger than $2^n$, the number of subsets
|
|
|
|
of the same set.
|
2017-01-07 14:35:53 +01:00
|
|
|
For example, if $n=20$, then
|
2017-02-16 22:31:26 +01:00
|
|
|
$n! \approx 2.4 \cdot 10^{18}$ and $2^n \approx 10^6$.
|
2017-02-04 21:47:12 +01:00
|
|
|
Hence, for certain values of $n$,
|
|
|
|
we can efficiently go through subsets but not through permutations.
|
2017-01-07 14:35:53 +01:00
|
|
|
|
2017-02-04 21:47:12 +01:00
|
|
|
As an example, consider the problem of
|
|
|
|
calculating the number of
|
|
|
|
permutations of a set $\{0,1,\ldots,n-1\}$,
|
|
|
|
where the difference between any two consecutive
|
2017-01-07 14:35:53 +01:00
|
|
|
elements is larger than one.
|
2017-02-04 21:47:12 +01:00
|
|
|
For example, when $n=4$, there are two such permutations:
|
|
|
|
$(1,3,0,2)$ and $(2,0,3,1)$.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-04 21:47:12 +01:00
|
|
|
Let $f(x,k)$ denote the number of valid permutations
|
2017-02-16 22:31:26 +01:00
|
|
|
of a subset $x$ where the last element is $k$ and
|
|
|
|
the difference between any two consecutive
|
2017-01-07 14:35:53 +01:00
|
|
|
elements is larger than one.
|
2017-02-04 21:47:12 +01:00
|
|
|
For example, $f(\{0,1,3\},1)=1$,
|
2017-01-07 14:35:53 +01:00
|
|
|
because there is a permutation $(0,3,1)$,
|
2017-02-04 21:47:12 +01:00
|
|
|
and $f(\{0,1,3\},3)=0$, because 0 and 1
|
|
|
|
cannot be next to each other.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-16 22:31:26 +01:00
|
|
|
Using $f$, the answer to the problem equals
|
|
|
|
\[ \sum_{i=0}^{n-1} f(\{0,1,\ldots,n-1\},i), \]
|
|
|
|
because the permutation has to contain all
|
|
|
|
elements $\{0,1,\ldots,n-1\}$ and the last
|
|
|
|
element can be any element.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-16 22:31:26 +01:00
|
|
|
The dynamic programming values can be stored as follows:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
2017-02-16 23:47:44 +01:00
|
|
|
int d[1<<n][n];
|
2016-12-28 23:54:51 +01:00
|
|
|
\end{lstlisting}
|
|
|
|
|
2017-01-07 14:35:53 +01:00
|
|
|
First, $f(\{k\},k)=1$ for all values of $k$:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
for (int i = 0; i < n; i++) d[1<<i][i] = 1;
|
|
|
|
\end{lstlisting}
|
|
|
|
|
2017-02-04 21:47:12 +01:00
|
|
|
Then, the other values can be calculated
|
2017-01-07 14:35:53 +01:00
|
|
|
as follows:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
|
|
|
for (int b = 0; b < (1<<n); b++) {
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
for (int j = 0; j < n; j++) {
|
|
|
|
if (abs(i-j) > 1 && (b&(1<<i)) && (b&(1<<j))) {
|
|
|
|
d[b][i] += d[b^(1<<i)][j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
\end{lstlisting}
|
|
|
|
|
2017-02-16 22:31:26 +01:00
|
|
|
In the above code,
|
|
|
|
the variable $b$ goes through all subsets and each
|
|
|
|
permutation is of the form $(\ldots,j,i)$,
|
2017-02-04 21:47:12 +01:00
|
|
|
where the difference between $i$ and $j$ is
|
|
|
|
larger than one and $i$ and $j$ belong to $b$.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 14:35:53 +01:00
|
|
|
Finally, the number of solutions can be
|
2017-02-04 21:47:12 +01:00
|
|
|
calculated as follows:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{lstlisting}
|
2017-02-16 23:47:44 +01:00
|
|
|
int s = 0;
|
2016-12-28 23:54:51 +01:00
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
s += d[(1<<n)-1][i];
|
|
|
|
}
|
|
|
|
\end{lstlisting}
|
|
|
|
|
2017-02-16 23:47:44 +01:00
|
|
|
\subsubsection{Counting subsets}
|
|
|
|
|
|
|
|
Our last problem in this chapter is as follows:
|
2017-02-16 23:50:04 +01:00
|
|
|
We are given a collection $C$ that consists of $m$ sets,
|
2017-02-16 23:47:44 +01:00
|
|
|
and our task is to determine for each set
|
2017-02-16 23:50:04 +01:00
|
|
|
the number of sets in $C$ that are its subsets.
|
2017-02-16 23:47:44 +01:00
|
|
|
For example, consider the following collection:
|
|
|
|
\[C = \{\{0\}, \{0,2\}, \{1,4\}, \{0,1,4\}, \{1,4,5\}\}\]
|
|
|
|
For any set $x$ in $C$,
|
|
|
|
let $f(x)$ denote the number of sets (including $x$) in $C$
|
|
|
|
that are subsets of $x$.
|
|
|
|
For example, $f(\{0,1,4\})=3$, because the
|
|
|
|
sets $\{0\}$, $\{1,4\}$ and $\{0,1,4\}$ are
|
|
|
|
subsets of $\{0,1,4\}$.
|
|
|
|
Using this notation, our task is to calculate the value of $f(x)$
|
|
|
|
for every set $x$ in the collection.
|
|
|
|
|
|
|
|
We will assume that each set is
|
|
|
|
a subset of $\{0,1,\ldots,n-1\}$.
|
|
|
|
Thus, the collection can contain at most
|
|
|
|
$2^n$ sets.
|
|
|
|
A straightforward way to solve the problem
|
|
|
|
is to go through all pairs of sets in the collection.
|
|
|
|
However, a more efficient solution is possible
|
|
|
|
using dynamic programming.
|
|
|
|
|
|
|
|
Let $c(x,k)$ denote the number of sets in
|
2017-02-16 23:50:04 +01:00
|
|
|
$C$ that equal a set $x$
|
2017-02-16 23:47:44 +01:00
|
|
|
if we are allowed to remove any subset of
|
|
|
|
$\{0,1,\ldots,k\}$ from $x$.
|
|
|
|
For example, in the above collection,
|
|
|
|
$c(\{0,1,4\},1)=2$,
|
|
|
|
where the corresponding sets are
|
|
|
|
$\{1,4\}$ and $\{0,1,4\}$.
|
|
|
|
|
|
|
|
It turns out that we can calculate all
|
|
|
|
values of $c(x,k)$ in $O(2^n n)$ time.
|
|
|
|
This solves our problem, because
|
|
|
|
\[f(x)=c(x,n-1).\]
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 14:35:53 +01:00
|
|
|
The base cases for the function are:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{equation*}
|
2017-02-16 23:47:44 +01:00
|
|
|
c(x,-1) = \begin{cases}
|
2017-02-16 23:55:36 +01:00
|
|
|
0 & \textrm{if $x \notin C$}\\
|
|
|
|
1 & \textrm{if $x \in C$}\\
|
2016-12-28 23:54:51 +01:00
|
|
|
\end{cases}
|
|
|
|
\end{equation*}
|
2017-01-07 14:35:53 +01:00
|
|
|
For larger values of $k$, the following recursion holds:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{equation*}
|
2017-02-16 23:47:44 +01:00
|
|
|
c(x,k) = \begin{cases}
|
|
|
|
c(x,k-1) & \textrm{if $k \notin x$}\\
|
|
|
|
c(x,k-1)+c(x \setminus \{k\},k-1) & \textrm{if $k \in x$}\\
|
2016-12-28 23:54:51 +01:00
|
|
|
\end{cases}
|
|
|
|
\end{equation*}
|
|
|
|
|
2017-02-16 23:47:44 +01:00
|
|
|
We can conveniently implement the algorithm by representing
|
|
|
|
the sets using bits.
|
|
|
|
Assume that there is an array
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{lstlisting}
|
2017-02-16 23:47:44 +01:00
|
|
|
int d[1<<n];
|
2016-12-28 23:54:51 +01:00
|
|
|
\end{lstlisting}
|
2017-02-16 23:47:44 +01:00
|
|
|
that is initialized so that $d[x]=1$ if $x$ belongs to $C$
|
|
|
|
and otherwise $d[x]=0$.
|
|
|
|
We can now implement the algorithm as follows:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{lstlisting}
|
|
|
|
for (int k = 0; k < n; k++) {
|
2017-02-16 23:47:44 +01:00
|
|
|
for (int b = 0; b < (1<<n); b++) {
|
|
|
|
if (b&(1<<k)) d[b] += d[b^(1<<k)];
|
2016-12-28 23:54:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
\end{lstlisting}
|
2017-02-16 23:47:44 +01:00
|
|
|
The above code is based on the recursive definition
|
2017-02-16 23:53:57 +01:00
|
|
|
of $c$. As a special trick, the code only uses
|
2017-02-16 23:47:44 +01:00
|
|
|
the array $d$ to calculate all values of the function.
|
|
|
|
Finally, for each set $x$ in $C$, $f(x)=d[x]$.
|
2016-12-28 23:54:51 +01:00
|
|
|
|