next up previous
Next: About this document ... Up: My Home Page

Learning to Count

Combinatorics problems are notorious for their reliance on cleverness and insight. Once you look at the problem in the right way, the answer suddenly becomes obvious.

Basic counting techniques include:

Double counting is a slippery aspect of combinatorics, which can make it difficult to solve problems via inclusion-exclusion.

Combinatorial Objects

A bijection is a one-to-one mapping between the elements of one set and the elements of another. Counting the size of one of the sets automatically gives you the size of the other set.

Exploiting bijections requires us to have a repertoire of sets which we know how to count, so we can map other objects to them.

It is useful to have a feeling for how fast the number of objects grows, to know when exhaustive search breaks down as a possible technique:

Recurrence Relations

Recurrence relations make it easy to count a variety of recursively defined structures. Recursively defined structures include trees, lists, well-formed formulae, and divide-and-conquer algorithms - so they lurk wherever computer scientists do.

A recurrence relation is an equation which is defined in terms of itself. They are useful because many natural functions are easily expressed as recurrences:

Polynomials:

\begin{displaymath}a_{n} = a_{n-1} + 1, a_{1} = 1 \longrightarrow a_{n} = n \end{displaymath}

Exponentials:

\begin{displaymath}a_{n} = 2 a_{n-1}, a_{1} = 2 \longrightarrow a_{n} = 2^{n} \end{displaymath}

Weird but interesting functions otherwise hard to represent:

\begin{displaymath}a_{n}=n a_{n-1}, a_{1} = 1 \longrightarrow a_{n} = n! \end{displaymath}

It is often easy to find a recurrence as the answer to a counting problem. Solving the recurrence to get a nice closed form can be somewhat of an art, but as we shall see, computer programs can easily evaluate the value of a given recurrence even without the existence of a nice closed form.

Binomial Coefficients

The most important class of counting numbers are the binomial coefficients, where $
{\scriptsize\left( \begin{array}{@{}c@{}} n \\ k \end{array} \right) }
$ counts the number of ways to choose $k$ things out of $n$ possibilities. What do they count?

Computing Binomial Coefficients

Since $
{\scriptsize\left( \begin{array}{@{}c@{}} n \\ k \end{array} \right) }
= n! / ((n-k)! k!)$, in principle you can compute them straight from factorials. However, intermediate calculations can easily cause arithmetic overflow even when the final coefficient fits comfortably within an integer.

A more stable way to compute binomial coefficients is using the recurrence relation implicit in the construction of Pascal's triangle, namely, that

\begin{displaymath}
{\scriptsize\left( \begin{array}{@{}c@{}} n \\ k \end{array}...
...e\left( \begin{array}{@{}c@{}} n-1 \\ k \end{array} \right) }
\end{displaymath}

Why does this work? Consider whether the $n$th element appears in one of the $
{\scriptsize\left( \begin{array}{@{}c@{}} n \\ k \end{array} \right) }
$ subsets of $k$ elements. If so, we can complete the subset by picking $k-1$ other items from the other $n-1$. If not, we must pick all $k$ items from the remaining $n-1$. There is no overlap between these cases, and all possibilities are included, so the sum counts all $k$-subsets.

No recurrence is complete without basis cases. How many ways are there to choose 0 things from a set? Exactly one, the empty set. The right term of the sum drives us up to $
{\scriptsize\left( \begin{array}{@{}c@{}} k \\ k \end{array} \right) }
$. How many ways are there to choose $k$ things from a $k$-element set? Exactly one, the complete set.

Implementation

The following implementation of this recurrence is a good example of programming techniques used in dynamic programming, namely storing a table of results so we can evaluate terms of the recurrence by looking up the appropriate values.


#define MAXN    100             /* largest n or m */

long binomial_coefficient(n,m)
int n,m;                        /* computer n choose m */
{
        int i,j;                /* counters */
        long bc[MAXN][MAXN];    /* table of binomial coefficients */

        for (i=0; i<=n; i++) bc[i][0] = 1;

        for (j=0; j<=n; j++) bc[j][j] = 1;

        for (i=1; i<=n; i++)
                for (j=1; j<i; j++)
                        bc[i][j] = bc[i-1][j-1] + bc[i-1][j];

        return( bc[n][m] );
}

Other Counting Sequences

Several other counting sequences which repeatedly emerge in applications, and which are easily computed using recurrence relations.

Assigned Problems

110603 (Counting) - How many ways can we express $n$ as the sum of 2s, 3s, and two types of 1?

110604 (Expressions) - How many ways can we build a well-formed formula from $n$ parentheses with nesting depth $d$?

110606 (The Priest Mathematician) - What is the best way to solve a 4-peg Tower of Hanoi puzzle?

110607 (Self-describing Sequence) - What is the $i$th value of the sequence containing $f(k)$ occurrences of $k$ for each $k$, i.e. 1, 2, 2, 3, 3, 4 ,4, 4, 5, 5, 6 ...? What if $i$ is too large to construct the entire sequence in memory?




next up previous
Next: About this document ... Up: My Home Page
Steve Skiena
2003-05-22