CSCI 2824: Lecture 27

We have two topics left over in counting/combinatorics that we will look at over the rest of this week.

  • Recursive Counting: counting things by establishing recurrence relations (Section 5.5 of the book)

  • Solving Recurrences: some basic ideas on generating functions for solving interesting recurrences (Section 5.6 of the book).

Recursive Counting

The idea behind recursive counting is to set up a recurrence that expresses what you wish to count. This is especially useful when what we wish to count does not neatly fit into any of the categories studied thus far.

Example-1

Q How many matches need to be played between n teams in a round-robin tournament?

You should know the answer to this problem by now and be able to reason it out in many different ways.

Answer

Let us look at it recursively. Let a_n be the number of matches for n teams. We know that

  • If n < 2 then a_n = 0. We need at least two teams to make it interesting!

  • Otherwise, a_2 = 1. Two teams will play exactly one match.

Can we now express a_n in terms of a_{n-1}?

Yes, we can say that with n teams, # of matches involving all n teams = # of matches involving teams 1… (n-1) + # of matches involving team n

Team n plays precisely n-1 matches (one with every other team). I.e, a_n = a_{n-1} + (n-1).

Therefore, the answer to the problem is governed by the recurrence relation:

  • a_n = a_{n-1} + (n-1) for n > 2

  • a_2 = 1.

The closed form solution is indeed {}^nC_2 = frac{n (n-1)}{2}.

Example-2

Q What is the number of n permutations of n objects?

In other words, what is {}^n P_n?

Answer

Let us write a recurrence (in the spirit of this lecture). To obtain a permutation of n objects (numbered 1…n), let us do the following:

  • Take away the last object and permute the remaining objects from 1 .. (n-1).

  • After this, we can decide where to insert the last object.

Step 1 yields {}^{n-1} P_{n-1} possible permutations (we pretend not to know what it may be :-) )

Once we have fixed a permutation of the first n-1 objects, there are n possible places where the object #n can be inserted. Therefore the recurrence is

  • {}^nP_n = n * {}^{n-1} P_{n-1}

  • The base case for 1 object is very simple, {}^1 P_1 = 1.

Once again, we know by eyeballing the recurrence that {}^n P_n = n!.

Example-3

How many solutions are there to the equation:

x_1 + ldots + x_n = r, mbox{where} n geq 1, r geq 0,  x_1,ldots,x_n geq 0.

Again, let us file under the category of things we already know how to solve by different methods :-)

Answer

Let T(n,r) represent the answer to this problem.

Simple cases:

  • Whenver r = 0, T(n,0) = 1 for all n. There is exactly one solution (set all x_1=x_2 = cdots = x_n = 0).

  • Whenever n=1, we have just one solution. Therefore, T(1,r) = 1 for all r.

Recurrence. We want to count the number of solutions T(n,r) for the general case where n > 1, r> 0. We have two cases:

  • Case-1: Assume x_n=0. Therefore, we can plug this in and take x_n out of the system.

    • This yields the system x_1 + cdots + x_{n-1} = r (x_n is set to zero, in other words).

  • Case-2: Set x_n geq 1. Following standard trick we saw last friday, we can write y_n +1 = x_n and remove x_n.

    • This yields the system x_1 + cdots + x_{n-1} + y_n +1 = r or alternatively x_1 + ldots + x_{n-1} + y_n = r -1 .

Any solution to the system either falls under case-1 or case-2. Therefore, we conclude that:  T(n,r) = T(n-1,r) + T(n,r-1).

Exercise Knowing secretly that T(n,r) = {}^{n+r-1}C_{r}, can we verify that the recurrence holds?

Example-4

We wish to roll a dice n times to obtain a sum of k. Each roll of the dice can give us a number from 1 to 6.

Q Let D(n,k) be the number of ways to obtain a sum of k from n rolls of a dice. Write a recurrence relation for D(n,k).

Answer

Let us get rid of the base cases.

  • n=1 and k=1,...,6. With one roll of the dice there is just one way to obtain an outcome of 1,2,3,4,5, or 6.

    • D(1,k) = 1, mbox{where} 1 leq k leq 6.

  • n=1 and k > 6. Can you tell me what D(1,k) ought to be?

  • k leq 1 and n > 1. Since we cannot turn up 0, we have D(n,k) = 0 whenever k leq 1 and n > 1.

Now for the generic case. Suppose we wish to roll the dice n times and arrive at a sum of exactly k. Let us split cases on the last roll:

  • The last roll showed up 1 and first n-1 rolls sum up to k-1.

  • The last roll shows up 2 and first n-1 rolls sum up to k-2

  • cdots

  • The last roll shows up to 6 and first n-1 rolls sum up to k-6.

Therefore, can we now write a recurrence to express the sum?

D(n,k) = D(n-1, k-1) + D(n-1,k-2) + cdots + D(n-1,k-6), n > 1, k geq 6 .

A recurrence should directly allow you to write an efficient program to compute the answer using dynamic programming.

Example-1

Let us take the following recurrence:

  • T(n,1) = 1 for all n > 0

  • T(1,r) = 1 for all r geq 0

  • T(n,r) = T(n-1,r) + T(n,r-1) if  r > 1 or  n > 1.

How do we solve it? We can write a program to compute T(n,r).

Program to compute T

 int T(int n, int r){
    assert( n > 1);
    assert( r > 1);
    /*-- Base Case --*/
    if ( r == 1) return 1;
    if ( n == 1) return 1;
    /* Recurrence */
    return T(n-1,r) + T(n,r-1);
 }

I implemented this in C and ran it. Here are the running times and some results:

n r Time (sec)
10 10 < .1 s
20 10 .1 s
15 15 .4 s
17 17 6 s
18 18 24 s
19 19 92 s
20 20   6 mins

We will explain how this recurrence can be computed faster in class.