Advanced Counting Problems and Techniques
Master problem-solving strategies including symmetry, bijections, double counting, and combinatorial proofs.
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 people around a circular table?
Linear arrangement: ways
Circular: Rotations are considered the same. Each circular arrangement corresponds to linear arrangements (rotate by 0, 1, 2, ..., positions).
For 5 people: circular arrangements.
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 , then (equal cardinality).
Strategy: To prove , construct a function that:
- Maps every element of to exactly one element of
- Every element of is the image of exactly one element of
Example 2: Binary Strings and Subsets
Claim: The number of binary strings of length equals the number of subsets of an -element set, both equal to .
Bijection: Map each subset to a binary string:
- Bit if
- Bit if
Example for :
This is a perfect bijection, so both sets have size .
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 people, each person shakes hands with others. Prove:
Two ways to count:
- By people: Each person contributes to the sum
- By handshakes: Each handshake involves 2 people
The sum counts each handshake twice (once per person), so:
Corollary: The sum of degrees in any graph is even!
Combinatorial Identities
Example 4: Vandermonde's Identity
Prove:
Combinatorial proof:
LHS: Choose people from a group of men and women.
RHS: Count by choosing men and women for each :
- 0 men, women:
- 1 man, women:
- ...
- men, 0 women:
Both count the same set!
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:
- Identify the structure: Ordered vs unordered? With/without repetition?
- Look for symmetry: Can you simplify via rotation, reflection, or equivalence?
- Try bijection: Can you map to a simpler, known problem?
- Consider cases: Break into disjoint scenarios (Rule of Sum)
- Use complementary counting: Sometimes is easier than
- 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
- Symmetry: Exploit rotational/reflectional symmetry (circular: )
- Bijection: One-to-one mapping proves equality of cardinalities
- Double counting: Count the same set two ways to prove identities
- Combinatorial proofs: Tell a counting story instead of manipulating formulas
- Systematic approach: Identify structure, look for patterns, verify with code
Next Module: Generating Functions - a powerful algebraic tool for counting!
Technique | Key Idea | Example |
|---|---|---|
| Symmetry | Equal counts for equivalent scenarios | Circular: $(n-1)!$ |
| Bijection | 1-to-1 mapping β equal sizes | Subsets β Binary strings |
| Double counting | Count same set two ways | Handshake lemma |
| Vandermonde | $\binom{m+n}{k} = \sum \binom{m}{i}\binom{n}{k-i}$ | Combinatorial identity |