Use 0-indexing with C++ arrays

This commit is contained in:
Antti H S Laaksonen 2017-04-17 17:59:27 +03:00
parent 11564fd4d3
commit 35d53d39d4
7 changed files with 616 additions and 635 deletions

View file

@ -22,9 +22,9 @@ dynamic programming, may be needed.
We first consider the problem of generating
all subsets of a set of $n$ elements.
For example, the subsets of $\{1,2,3\}$ are
$\emptyset$, $\{1\}$, $\{2\}$, $\{3\}$, $\{1,2\}$,
$\{1,3\}$, $\{2,3\}$ and $\{1,2,3\}$.
For example, the subsets of $\{0,1,2\}$ are
$\emptyset$, $\{0\}$, $\{1\}$, $\{2\}$, $\{0,1\}$,
$\{0,2\}$, $\{1,2\}$ and $\{0,1,2\}$.
There are two common methods for this:
we can either implement a recursive search
or use bit operations of integers.
@ -35,21 +35,21 @@ An elegant way to go through all subsets
of a set is to use recursion.
The following function
generates the subsets of the set
$\{1,2,\ldots,n\}$.
The function maintains a vector \texttt{v}
$\{0,1,\ldots,n-1\}$.
The function maintains a vector \texttt{subset}
that will contain the elements of each subset.
The search begins when the function is called
with parameter 1.
with parameter 0.
\begin{lstlisting}
void gen(int k) {
if (k == n+1) {
// process subset v
if (k == n) {
// process subset
} else {
gen(k+1);
v.push_back(k);
subset.push_back(k);
gen(k+1);
v.pop_back();
subset.pop_back();
}
}
\end{lstlisting}
@ -59,7 +59,7 @@ candidate to be included in the subset.
The function considers two cases that both
generate a recursive call:
either $k$ is included or not included in the subset.
Finally, when $k=n+1$, all elements have been processed
Finally, when $k=n$, all elements have been processed
and one subset has been generated.
The following tree illustrates how the function is
@ -72,41 +72,41 @@ We can always choose either the left branch
\begin{tikzpicture}[scale=.45]
\begin{scope}
\small
\node at (0,0) {$\texttt{gen}(1)$};
\node at (0,0) {$\texttt{gen}(0)$};
\node at (-8,-4) {$\texttt{gen}(2)$};
\node at (8,-4) {$\texttt{gen}(2)$};
\node at (-8,-4) {$\texttt{gen}(1)$};
\node at (8,-4) {$\texttt{gen}(1)$};
\path[draw,thick,->] (0,0-0.5) -- (-8,-4+0.5);
\path[draw,thick,->] (0,0-0.5) -- (8,-4+0.5);
\node at (-12,-8) {$\texttt{gen}(3)$};
\node at (-4,-8) {$\texttt{gen}(3)$};
\node at (4,-8) {$\texttt{gen}(3)$};
\node at (12,-8) {$\texttt{gen}(3)$};
\node at (-12,-8) {$\texttt{gen}(2)$};
\node at (-4,-8) {$\texttt{gen}(2)$};
\node at (4,-8) {$\texttt{gen}(2)$};
\node at (12,-8) {$\texttt{gen}(2)$};
\path[draw,thick,->] (-8,-4-0.5) -- (-12,-8+0.5);
\path[draw,thick,->] (-8,-4-0.5) -- (-4,-8+0.5);
\path[draw,thick,->] (8,-4-0.5) -- (4,-8+0.5);
\path[draw,thick,->] (8,-4-0.5) -- (12,-8+0.5);
\node at (-14,-12) {$\texttt{gen}(4)$};
\node at (-10,-12) {$\texttt{gen}(4)$};
\node at (-6,-12) {$\texttt{gen}(4)$};
\node at (-2,-12) {$\texttt{gen}(4)$};
\node at (2,-12) {$\texttt{gen}(4)$};
\node at (6,-12) {$\texttt{gen}(4)$};
\node at (10,-12) {$\texttt{gen}(4)$};
\node at (14,-12) {$\texttt{gen}(4)$};
\node at (-14,-12) {$\texttt{gen}(3)$};
\node at (-10,-12) {$\texttt{gen}(3)$};
\node at (-6,-12) {$\texttt{gen}(3)$};
\node at (-2,-12) {$\texttt{gen}(3)$};
\node at (2,-12) {$\texttt{gen}(3)$};
\node at (6,-12) {$\texttt{gen}(3)$};
\node at (10,-12) {$\texttt{gen}(3)$};
\node at (14,-12) {$\texttt{gen}(3)$};
\node at (-14,-13.5) {$\emptyset$};
\node at (-10,-13.5) {$\{3\}$};
\node at (-6,-13.5) {$\{2\}$};
\node at (-2,-13.5) {$\{2,3\}$};
\node at (2,-13.5) {$\{1\}$};
\node at (6,-13.5) {$\{1,3\}$};
\node at (10,-13.5) {$\{1,2\}$};
\node at (14,-13.5) {$\{1,2,3\}$};
\node at (-10,-13.5) {$\{2\}$};
\node at (-6,-13.5) {$\{1\}$};
\node at (-2,-13.5) {$\{1,2\}$};
\node at (2,-13.5) {$\{0\}$};
\node at (6,-13.5) {$\{0,2\}$};
\node at (10,-13.5) {$\{0,1\}$};
\node at (14,-13.5) {$\{0,1,2\}$};
\path[draw,thick,->] (-12,-8-0.5) -- (-14,-12+0.5);
@ -135,14 +135,14 @@ The usual convention is that the $k$th element
is included in the subset exactly when the $k$th last bit
in the sequence is one.
For example, the bit representation of 25
is 11001, that corresponds to the subset $\{1,4,5\}$.
is 11001, that corresponds to the subset $\{0,3,4\}$.
The following code goes through all subsets
of a set of $n$ elements
\begin{lstlisting}
for (int b = 0; b < (1<<n); b++) {
// process subset b
// process subset
}
\end{lstlisting}
@ -154,9 +154,9 @@ elements in the subset.
\begin{lstlisting}
for (int b = 0; b < (1<<n); b++) {
vector<int> v;
vector<int> subset;
for (int i = 0; i < n; i++) {
if (b&(1<<i)) v.push_back(i+1);
if (b&(1<<i)) subset.push_back(i);
}
}
\end{lstlisting}
@ -167,9 +167,9 @@ for (int b = 0; b < (1<<n); b++) {
Next we will consider the problem of generating
all permutations of a set of $n$ elements.
For example, the permutations of $\{1,2,3\}$ are
$(1,2,3)$, $(1,3,2)$, $(2,1,3)$, $(2,3,1)$,
$(3,1,2)$ and $(3,2,1)$.
For example, the permutations of $\{0,1,2\}$ are
$(0,1,2)$, $(0,2,1)$, $(1,0,2)$, $(1,2,0)$,
$(2,0,1)$ and $(2,1,0)$.
Again, there are two approaches:
we can either use recursion or go through the
permutations iteratively.
@ -179,36 +179,34 @@ permutations iteratively.
Like subsets, permutations can be generated
using recursion.
The following function goes
through the permutations of the set $\{1,2,\ldots,n\}$.
The function builds a vector \texttt{v} that contains
through the permutations of the set $\{0,1,\ldots,n-1\}$.
The function builds a vector \texttt{perm} that contains
the elements in the permutation,
and the search begins when the function is
called without parameters.
\begin{lstlisting}
void gen() {
if (v.size() == n) {
// process permutation v
if (perm.size() == n) {
// process permutation
} else {
for (int i = 1; i <= n; i++) {
if (p[i]) continue;
p[i] = 1;
v.push_back(i);
for (int i = 0; i < n; i++) {
if (chosen[i]) continue;
chosen[i] = true;
perm.push_back(i);
gen();
p[i] = 0;
v.pop_back();
chosen[i] = false;
perm.pop_back();
}
}
}
\end{lstlisting}
Each function call adds a new element to
the vector \texttt{v}.
The array \texttt{p} indicates which
elements are already included in the permutation:
if $\texttt{p}[k]=0$, element $k$ is not included,
and if $\texttt{p}[k]=1$, element $k$ is included.
If the size of \texttt{v} equals the size of the set,
the vector \texttt{perm}.
The array \texttt{chosen} indicates which
elements are already included in the permutation.
If the size of \texttt{perm} equals the size of the set,
a permutation has been generated.
\subsubsection{Method 2}
@ -224,13 +222,13 @@ The C++ standard library contains the function
\texttt{next\_permutation} that can be used for this:
\begin{lstlisting}
vector<int> v;
for (int i = 1; i <= n; i++) {
v.push_back(i);
vector<int> perm;
for (int i = 0; i < n; i++) {
perm.push_back(i);
}
do {
// process permutation v
} while (next_permutation(v.begin(),v.end()));
// process permutation
} while (next_permutation(perm.begin(),perm.end()));
\end{lstlisting}
\section{Backtracking}
@ -344,7 +342,7 @@ The following code implements the search:
\begin{lstlisting}
void search(int y) {
if (y == n) {
c++;
count++;
return;
}
for (int x = 0; x < n; x++) {
@ -359,7 +357,7 @@ void search(int y) {
The search begins by calling \texttt{search(0)}.
The size of the board is $n$,
and the code calculates the number of solutions
to $c$.
to \texttt{count}.
The code assumes that the rows and columns
of the board are numbered from 0.