Counting subsets
This commit is contained in:
parent
c215e415cd
commit
21e36525e2
123
luku10.tex
123
luku10.tex
|
@ -427,7 +427,7 @@ element can be any element.
|
||||||
|
|
||||||
The dynamic programming values can be stored as follows:
|
The dynamic programming values can be stored as follows:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
long long d[1<<n][n];
|
int d[1<<n][n];
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
First, $f(\{k\},k)=1$ for all values of $k$:
|
First, $f(\{k\},k)=1$ for all values of $k$:
|
||||||
|
@ -459,93 +459,86 @@ Finally, the number of solutions can be
|
||||||
calculated as follows:
|
calculated as follows:
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
long long s = 0;
|
int s = 0;
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
s += d[(1<<n)-1][i];
|
s += d[(1<<n)-1][i];
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
\subsubsection{Sums of subsets}
|
\subsubsection{Counting subsets}
|
||||||
|
|
||||||
As the last example, we consider the following problem:
|
Our last problem in this chapter is as follows:
|
||||||
Each subset $x$
|
We are given a collection $C$ of $m$ sets,
|
||||||
of $\{0,1,\ldots,n-1\}$
|
and our task is to determine for each set
|
||||||
is assigned a value $c(x)$,
|
the number of sets that are its subsets.
|
||||||
and our task is to calculate for
|
For example, consider the following collection:
|
||||||
each subset $x$ the sum
|
\[C = \{\{0\}, \{0,2\}, \{1,4\}, \{0,1,4\}, \{1,4,5\}\}\]
|
||||||
\[s(x)=\sum_{y \subset x} c(y).\]
|
For any set $x$ in $C$,
|
||||||
Using bit operations, the corresponding sum is
|
let $f(x)$ denote the number of sets (including $x$) in $C$
|
||||||
\[s(x)=\sum_{y \& x = y} c(y).\]
|
that are subsets of $x$.
|
||||||
For example, the functions could be
|
For example, $f(\{0,1,4\})=3$, because the
|
||||||
as follows when $n=3$:
|
sets $\{0\}$, $\{1,4\}$ and $\{0,1,4\}$ are
|
||||||
\begin{center}
|
subsets of $\{0,1,4\}$.
|
||||||
\begin{tabular}{rrr}
|
Using this notation, our task is to calculate the value of $f(x)$
|
||||||
$x$ & $c(x)$ & $s(x)$ \\
|
for every set $x$ in the collection.
|
||||||
\hline
|
|
||||||
000 & 2 & 2 \\
|
|
||||||
001 & 0 & 2 \\
|
|
||||||
010 & 1 & 3 \\
|
|
||||||
011 & 3 & 6 \\
|
|
||||||
100 & 0 & 2 \\
|
|
||||||
101 & 4 & 6 \\
|
|
||||||
110 & 2 & 5 \\
|
|
||||||
111 & 0 & 12 \\
|
|
||||||
\end{tabular}
|
|
||||||
\end{center}
|
|
||||||
For example, $s(110)=c(000)+c(010)+c(100)+c(110)=5$.
|
|
||||||
|
|
||||||
The problem can be solved in $O(2^n n)$ time
|
We will assume that each set is
|
||||||
by defining a function $f(x,k)$ that calculates
|
a subset of $\{0,1,\ldots,n-1\}$.
|
||||||
the sum of $c(y)$ values such that $x$ can be
|
Thus, the collection can contain at most
|
||||||
turned into $y$ by changing zero or more one bits
|
$2^n$ sets.
|
||||||
at positions $0,1,\ldots,k$ to zero bits.
|
A straightforward way to solve the problem
|
||||||
Using this function, the solution to the
|
is to go through all pairs of sets in the collection.
|
||||||
problem is $s(x)=f(x,n-1)$.
|
However, a more efficient solution is possible
|
||||||
|
using dynamic programming.
|
||||||
|
|
||||||
|
Let $c(x,k)$ denote the number of sets in
|
||||||
|
$C$ that equal to a set $x$
|
||||||
|
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).\]
|
||||||
|
|
||||||
The base cases for the function are:
|
The base cases for the function are:
|
||||||
\begin{equation*}
|
\begin{equation*}
|
||||||
f(x,0) = \begin{cases}
|
c(x,-1) = \begin{cases}
|
||||||
c(x) & \textrm{if bit 0 of $x$ is 0}\\
|
0 & \textrm{if $x$ does not appear in $C$}\\
|
||||||
c(x)+c(x \XOR 1) & \textrm{if bit 0 of $x$ is 1}\\
|
1 & \textrm{if $x$ appears in $C$}\\
|
||||||
\end{cases}
|
\end{cases}
|
||||||
\end{equation*}
|
\end{equation*}
|
||||||
For larger values of $k$, the following recursion holds:
|
For larger values of $k$, the following recursion holds:
|
||||||
\begin{equation*}
|
\begin{equation*}
|
||||||
f(x,k) = \begin{cases}
|
c(x,k) = \begin{cases}
|
||||||
f(x,k-1) & \textrm{if bit $k$ of $x$ is 0}\\
|
c(x,k-1) & \textrm{if $k \notin x$}\\
|
||||||
f(x,k-1)+f(x \XOR (1 < < k),k-1) & \textrm{if bit $k$ of $x$ is 1}\\
|
c(x,k-1)+c(x \setminus \{k\},k-1) & \textrm{if $k \in x$}\\
|
||||||
\end{cases}
|
\end{cases}
|
||||||
\end{equation*}
|
\end{equation*}
|
||||||
|
|
||||||
Thus, we can calculate the values of the function
|
We can conveniently implement the algorithm by representing
|
||||||
as follows using dynamic programming.
|
the sets using bits.
|
||||||
The code assumes that the array \texttt{c}
|
Assume that there is an array
|
||||||
contains the values for $c$,
|
|
||||||
and it constructs an array \texttt{s}
|
|
||||||
that contains the values for $s$.
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
for (int x = 0; x < (1<<n); x++) {
|
int d[1<<n];
|
||||||
f[x][0] = c[x];
|
|
||||||
if (x&1) f[x][0] += c[x^1];
|
|
||||||
}
|
|
||||||
for (int k = 1; k < n; k++) {
|
|
||||||
for (int x = 0; x < (1<<n); x++) {
|
|
||||||
f[x][k] = f[x][k-1];
|
|
||||||
if (b&(1<<k)) f[x][k] += f[x^(1<<k)][k-1];
|
|
||||||
}
|
|
||||||
if (k == n-1) s[x] = f[x][k];
|
|
||||||
}
|
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
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:
|
||||||
|
|
||||||
Actually, a much shorter implementation is possible,
|
|
||||||
because we can calculate the results directly
|
|
||||||
into the array \texttt{s}:
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
for (int x = 0; x < (1<<n); x++) s[x] = c[x];
|
|
||||||
for (int k = 0; k < n; k++) {
|
for (int k = 0; k < n; k++) {
|
||||||
for (int x = 0; x < (1<<n); x++) {
|
for (int b = 0; b < (1<<n); b++) {
|
||||||
if (x&(1<<k)) s[x] += s[x^(1<<k)];
|
if (b&(1<<k)) d[b] += d[b^(1<<k)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
The above code is based on the recursive definition
|
||||||
|
of $c$. As a special trick, the function only uses
|
||||||
|
the array $d$ to calculate all values of the function.
|
||||||
|
Finally, for each set $x$ in $C$, $f(x)=d[x]$.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue