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\}$,
|
2017-05-22 22:32:52 +02:00
|
|
|
and then constructs 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-05-22 22:32:52 +02:00
|
|
|
\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.
|
2017-05-23 21:09:51 +02:00
|
|
|
In this section we discuss two examples
|
2017-05-22 22:32:52 +02:00
|
|
|
of such situations.
|
|
|
|
|
|
|
|
\subsubsection{Hamming distances}
|
|
|
|
|
|
|
|
\index{Hamming distance}
|
2017-05-23 21:09:51 +02:00
|
|
|
The \key{Hamming distance}
|
|
|
|
$\texttt{hamming}(a,b)$ between two
|
|
|
|
equal-length bit strings $a$ and $b$ is
|
2017-05-22 22:32:52 +02:00
|
|
|
the number of positions where the strings differ.
|
2017-05-23 21:09:51 +02:00
|
|
|
For example, $\texttt{hamming}(01101,11001)=2$.
|
2017-05-22 22:32:52 +02:00
|
|
|
|
2017-05-23 21:09:51 +02:00
|
|
|
Consider the following problem: Given
|
2017-05-22 22:32:52 +02:00
|
|
|
a list of $n$ bit strings, each of length $k$,
|
2017-05-23 21:09:51 +02:00
|
|
|
calculate the minimum Hamming distance
|
2017-05-22 22:32:52 +02:00
|
|
|
between two strings in the list.
|
2017-05-23 21:09:51 +02:00
|
|
|
For example, the answer for $[00111,01101,11110]$,
|
|
|
|
is 2, because
|
|
|
|
\begin{itemize}[noitemsep]
|
|
|
|
\item $\texttt{hamming}(00111,01101)=2$,
|
|
|
|
\item $\texttt{hamming}(00111,11110)=3$, and
|
|
|
|
\item $\texttt{hamming}(01101,11110)=3$.
|
|
|
|
\end{itemize}
|
2017-05-22 22:32:52 +02:00
|
|
|
|
|
|
|
A straightforward way to solve the problem is
|
|
|
|
to go through all pairs of string and calculate
|
2017-05-23 21:09:51 +02:00
|
|
|
their Hamming distances,
|
|
|
|
which yields an $O(n^2 k)$ time algorithm.
|
|
|
|
The following function calculates
|
2017-05-22 22:32:52 +02:00
|
|
|
the Hamming distance between two strings:
|
|
|
|
\begin{lstlisting}
|
2017-05-23 21:09:51 +02:00
|
|
|
int hamming(string a, string b) {
|
2017-05-22 22:32:52 +02:00
|
|
|
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}
|
2017-05-23 21:09:51 +02:00
|
|
|
int hamming(int a, int b) {
|
2017-05-22 22:32:52 +02:00
|
|
|
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,
|
2017-05-23 21:09:51 +02:00
|
|
|
it only took 0.5 seconds.
|
2017-05-22 22:32:52 +02:00
|
|
|
Thus, the bit optimized code was almost
|
|
|
|
30 times faster than the original code.
|
|
|
|
|
2017-05-23 21:09:51 +02:00
|
|
|
\subsubsection{Counting subgrids}
|
|
|
|
|
|
|
|
As another example, consider the
|
|
|
|
following problem:
|
|
|
|
Given an $n \times n$ grid whose
|
|
|
|
each square is either black or white,
|
|
|
|
calculate the number of subgrids
|
|
|
|
whose all corners are black.
|
|
|
|
For example, the grid
|
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.5]
|
|
|
|
\fill[black] (1,1) rectangle (2,2);
|
|
|
|
\fill[black] (1,4) rectangle (2,5);
|
|
|
|
\fill[black] (4,1) rectangle (5,2);
|
|
|
|
\fill[black] (4,4) rectangle (5,5);
|
|
|
|
\fill[black] (1,3) rectangle (2,4);
|
|
|
|
\fill[black] (2,3) rectangle (3,4);
|
|
|
|
\fill[black] (2,1) rectangle (3,2);
|
|
|
|
\fill[black] (0,2) rectangle (1,3);
|
|
|
|
\draw (0,0) grid (5,5);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
contains two such subgrids:
|
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.5]
|
|
|
|
\fill[black] (1,1) rectangle (2,2);
|
|
|
|
\fill[black] (1,4) rectangle (2,5);
|
|
|
|
\fill[black] (4,1) rectangle (5,2);
|
|
|
|
\fill[black] (4,4) rectangle (5,5);
|
|
|
|
\fill[black] (1,3) rectangle (2,4);
|
|
|
|
\fill[black] (2,3) rectangle (3,4);
|
|
|
|
\fill[black] (2,1) rectangle (3,2);
|
|
|
|
\fill[black] (0,2) rectangle (1,3);
|
|
|
|
\draw (0,0) grid (5,5);
|
|
|
|
|
|
|
|
\fill[black] (7+1,1) rectangle (7+2,2);
|
|
|
|
\fill[black] (7+1,4) rectangle (7+2,5);
|
|
|
|
\fill[black] (7+4,1) rectangle (7+5,2);
|
|
|
|
\fill[black] (7+4,4) rectangle (7+5,5);
|
|
|
|
\fill[black] (7+1,3) rectangle (7+2,4);
|
|
|
|
\fill[black] (7+2,3) rectangle (7+3,4);
|
|
|
|
\fill[black] (7+2,1) rectangle (7+3,2);
|
|
|
|
\fill[black] (7+0,2) rectangle (7+1,3);
|
|
|
|
\draw (7+0,0) grid (7+5,5);
|
|
|
|
|
|
|
|
\draw[color=red,line width=1mm] (1,1) rectangle (3,4);
|
|
|
|
\draw[color=red,line width=1mm] (7+1,1) rectangle (7+5,5);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
|
|
|
|
There is an $O(n^3)$ time algorithm for solving the problem:
|
|
|
|
go through all $O(n^2)$ pairs of rows and for each pair
|
|
|
|
calculate the number of columns that contain a black
|
|
|
|
square in both rows in $O(n)$ time.
|
|
|
|
Then, if there are $c$ such columns for a fixed row pair,
|
|
|
|
they account for $c(c-1)/2$ subgrids with black corners.
|
|
|
|
|
|
|
|
To optimize this algorithm, we divide the grid into blocks
|
|
|
|
of columns such that each block consists of $N$
|
|
|
|
consecutive columns. Then, each row is stored as
|
|
|
|
a list of $N$-bit numbers that describe the colors
|
|
|
|
of the squares.
|
|
|
|
Using this representation,
|
|
|
|
we can process $N$ columns at the same time
|
|
|
|
using bit operations, and the resulting algorithm
|
|
|
|
works in $O(n^3/N)$ time.
|
|
|
|
|
|
|
|
We generated a random grid of size $2500 \times 2500$
|
|
|
|
and compared the original and bit-optimized implementation.
|
|
|
|
While the original code took $29.6$ seconds,
|
|
|
|
the bit-optimized version only took $3.1$ seconds
|
|
|
|
with $N=32$ (\texttt{int} numbers) and $1.7$ seconds
|
|
|
|
with $N=64$ (\texttt{long long} numbers).
|
2017-05-22 22:32:52 +02:00
|
|
|
|
2017-01-07 14:35:53 +01:00
|
|
|
\section{Dynamic programming}
|
|
|
|
|
2017-05-23 23:13:02 +02:00
|
|
|
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}
|
|
|
|
|
2017-01-07 14:35:53 +01:00
|
|
|
\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-05-22 22:32:52 +02:00
|
|
|
The benefit of 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-05-22 22:32:52 +02:00
|
|
|
As an example, consider the following problem:
|
|
|
|
There is an elevator with maximum weight $x$,
|
|
|
|
and $n$ people with known weights
|
|
|
|
who want to get from the ground floor
|
|
|
|
to the top floor.
|
|
|
|
What is the minimum number of rides needed
|
|
|
|
if the people enter the elevator in an optimal order?
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-05-22 22:32:52 +02:00
|
|
|
For example, suppose that $x=10$, $n=5$
|
|
|
|
and the weights are as follows:
|
|
|
|
\begin{center}
|
|
|
|
\begin{tabular}{ll}
|
|
|
|
person & weight \\
|
|
|
|
\hline
|
|
|
|
$A$ & 2 \\
|
|
|
|
$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).
|
|
|
|
|
|
|
|
The problem can be easily solved in $O(n! n)$ time
|
|
|
|
by testing all possible permutations of $n$ people.
|
|
|
|
However, we can use dynamic programming to get
|
|
|
|
a more efficient $O(2^n n)$ time algorithm.
|
|
|
|
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.
|
|
|
|
|
|
|
|
Let $\texttt{rides}(X)$ denote the minimum number
|
|
|
|
of rides and $\texttt{weight}(X)$ denote the minimum
|
|
|
|
weight of the last group, where $X$ is a subset
|
|
|
|
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.
|
|
|
|
|
|
|
|
It turns out that we can calculate the values
|
|
|
|
of the functions recursively and then apply
|
|
|
|
dynamic programming.
|
|
|
|
The idea is to go through all people
|
|
|
|
that belong to $X$ and optimally
|
|
|
|
choose the last person who enters the elevator.
|
|
|
|
For example, if $X=\{B,D,E\}$,
|
|
|
|
one of $B$, $D$ and $E$ is the last person
|
|
|
|
who enters the elevator.
|
|
|
|
Each such choice yields a subproblem
|
|
|
|
for a smaller subset of people.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
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
|
|
|
|