Advanced Counting Problems and Techniques

Master problem-solving strategies including symmetry, bijections, double counting, and combinatorial proofs.

26 min read
Intermediate

Introduction

Mastering combinatorics requires more than formulas - it demands problem-solving strategies. In this lesson, we'll tackle advanced counting problems using techniques like symmetry arguments, bijective reasoning, and clever decompositions.

Learning Objectives:

  • Apply combinatorial arguments to complex problems
  • Use symmetry to simplify counting
  • Construct bijections between sets
  • Develop systematic problem-solving approaches

Symmetry Arguments

Symmetry can dramatically simplify counting problems by showing that multiple scenarios have equal counts.

Example 1: Circular Arrangements

How many ways to arrange nn people around a circular table?

Linear arrangement: n!n! ways

Circular: Rotations are considered the same. Each circular arrangement corresponds to nn linear arrangements (rotate by 0, 1, 2, ..., nβˆ’1n-1 positions).

n!n=(nβˆ’1)!\frac{n!}{n} = (n-1)!

For 5 people: (5βˆ’1)!=4!=24(5-1)! = 4! = 24 circular arrangements.

python
import math

def circular_permutations(n):
    """Circular arrangements of n distinct objects"""
    return math.factorial(n - 1) if n > 0 else 0

# Circular seating for 5 people
n = 5
linear = math.factorial(n)
circular = circular_permutations(n)

print(f"Linear arrangements of {n} people: {linear:,}")
print(f"Circular arrangements of {n} people: {circular:,}")
print(f"\nRatio: {linear} / {circular} = {linear // circular}")
print(f"Each circular arrangement = {n} rotations of a linear arrangement")

# Example with names
people = ['Alice', 'Bob', 'Carol', 'Dave', 'Eve']
print(f"\nCircular arrangements: (n-1)! = {len(people)-1}! = {circular}")

Bijective Proofs

A bijection is a one-to-one correspondence between two sets. If we can construct a bijection f:Aβ†’Bf: A \rightarrow B, then ∣A∣=∣B∣|A| = |B| (equal cardinality).

Strategy: To prove ∣A∣=∣B∣|A| = |B|, construct a function ff that:

  1. Maps every element of AA to exactly one element of BB
  2. Every element of BB is the image of exactly one element of AA

Example 2: Binary Strings and Subsets

Claim: The number of binary strings of length nn equals the number of subsets of an nn-element set, both equal to 2n2^n.

Bijection: Map each subset SβŠ†{1,2,...,n}S \subseteq \{1, 2, ..., n\} to a binary string:

  • Bit i=1i = 1 if i∈Si \in S
  • Bit i=0i = 0 if iβˆ‰Si \notin S

Example for n=3n=3:

  • βˆ…β†”000\emptyset \leftrightarrow 000
  • {1}↔100\{1\} \leftrightarrow 100
  • {2,3}↔011\{2, 3\} \leftrightarrow 011
  • {1,2,3}↔111\{1, 2, 3\} \leftrightarrow 111

This is a perfect bijection, so both sets have size 23=82^3 = 8.

python
def subset_to_binary(subset, n):
    """Convert subset to binary string"""
    binary = ['0'] * n
    for elem in subset:
        binary[elem - 1] = '1'
    return ''.join(binary)

def binary_to_subset(binary_str):
    """Convert binary string to subset"""
    return {i + 1 for i, bit in enumerate(binary_str) if bit == '1'}

# Demonstrate bijection for n=3
n = 3
all_subsets = [
    set(), {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}
]

print(f"Bijection between subsets and binary strings (n={n}):")
print(f"{'Subset':<15} ↔ {'Binary'}")
print("-" * 30)

for subset in all_subsets:
    binary = subset_to_binary(subset, n)
    recovered = binary_to_subset(binary)
    print(f"{str(subset):<15} ↔ {binary}  (verify: {subset == recovered})")

print(f"\nTotal count: {len(all_subsets)} = 2^{n} = {2**n}")

Double Counting

Double counting proves identities by counting the same set in two different ways.

Example 3: Handshake Lemma

At a party with nn people, each person shakes hands with did_i others. Prove:

βˆ‘i=1ndi=2β‹…(numberΒ ofΒ handshakes)\sum_{i=1}^{n} d_i = 2 \cdot (\text{number of handshakes})

Two ways to count:

  1. By people: Each person ii contributes did_i to the sum
  2. By handshakes: Each handshake involves 2 people

The sum counts each handshake twice (once per person), so:

βˆ‘di=2Γ—(handshakes)\sum d_i = 2 \times \text{(handshakes)}

Corollary: The sum of degrees in any graph is even!

Combinatorial Identities

Example 4: Vandermonde's Identity

Prove:

(m+nk)=βˆ‘i=0k(mi)(nkβˆ’i)\binom{m+n}{k} = \sum_{i=0}^{k} \binom{m}{i} \binom{n}{k-i}

Combinatorial proof:

LHS: Choose kk people from a group of mm men and nn women.

RHS: Count by choosing ii men and kβˆ’ik-i women for each i=0,1,...,ki = 0, 1, ..., k:

  • 0 men, kk women: (m0)(nk)\binom{m}{0} \binom{n}{k}
  • 1 man, kβˆ’1k-1 women: (m1)(nkβˆ’1)\binom{m}{1} \binom{n}{k-1}
  • ...
  • kk men, 0 women: (mk)(n0)\binom{m}{k} \binom{n}{0}

Both count the same set!

python
from scipy.special import comb

def verify_vandermonde(m, n, k):
    """Verify Vandermonde's identity"""
    # LHS: C(m+n, k)
    lhs = int(comb(m + n, k, exact=True))

    # RHS: sum of C(m,i) * C(n, k-i) for i = 0 to k
    rhs = 0
    terms = []
    for i in range(k + 1):
        if i <= m and (k - i) <= n:
            term = int(comb(m, i, exact=True)) * int(comb(n, k - i, exact=True))
            rhs += term
            terms.append((i, k-i, term))

    return lhs, rhs, terms

# Verify for m=5, n=4, k=3
m, n, k = 5, 4, 3
lhs, rhs, terms = verify_vandermonde(m, n, k)

print(f"Vandermonde's Identity: C({m}+{n}, {k}) = Ξ£ C({m},i)Β·C({n},{k}-i)")
print(f"\nLHS: C({m+n}, {k}) = {lhs}")
print(f"\nRHS breakdown:")
for i, j, term in terms:
    print(f"  i={i}: C({m},{i}) Γ— C({n},{j}) = {int(comb(m,i,exact=True))} Γ— {int(comb(n,j,exact=True))} = {term}")
print(f"\nRHS total: {rhs}")
print(f"\nVerified: {lhs} = {rhs} βœ“" if lhs == rhs else f"Failed: {lhs} β‰  {rhs}")

Problem-Solving Framework

When facing a combinatorics problem:

  1. Identify the structure: Ordered vs unordered? With/without repetition?
  2. Look for symmetry: Can you simplify via rotation, reflection, or equivalence?
  3. Try bijection: Can you map to a simpler, known problem?
  4. Consider cases: Break into disjoint scenarios (Rule of Sum)
  5. Use complementary counting: Sometimes ∣Ac∣|A^c| is easier than ∣A∣|A|
  6. Verify computationally: Enumerate small cases to check your reasoning

Practice Strategy: Work through problems multiple ways. An algebraic proof and a combinatorial proof give different insights. Computational verification builds confidence.

Key Takeaways

  1. Symmetry: Exploit rotational/reflectional symmetry (circular: (nβˆ’1)!(n-1)!)
  2. Bijection: One-to-one mapping proves equality of cardinalities
  3. Double counting: Count the same set two ways to prove identities
  4. Combinatorial proofs: Tell a counting story instead of manipulating formulas
  5. Systematic approach: Identify structure, look for patterns, verify with code

Next Module: Generating Functions - a powerful algebraic tool for counting!

Technique
Key Idea
Example
SymmetryEqual counts for equivalent scenariosCircular: $(n-1)!$
Bijection1-to-1 mapping β†’ equal sizesSubsets ↔ Binary strings
Double countingCount same set two waysHandshake lemma
Vandermonde$\binom{m+n}{k} = \sum \binom{m}{i}\binom{n}{k-i}$Combinatorial identity