Project Euler Problem 215
Consider the problem of building a wall out of 2 times 1 and 3 times 1 bricks (text{horizontal} times text{vertical} dim
Solution
Answer: 806844323190414
Let $W(w,h)$ denote the number of crack-free walls of width $w$ and height $h$.
We must compute $W(32,10)$.
The key observation is:
- A row is determined entirely by the positions of its internal vertical cracks.
- Two rows are compatible iff they share no crack positions.
- Thus the problem becomes:
- Generate all valid rows of width $32$,
- Build a compatibility graph,
- Count length-10 paths in that graph.
Step 1 — Representing a row
Bricks are $2\times1$ and $3\times1$, placed horizontally.
A row of width $w$ is any composition of $w$ using 2s and 3s.
Example for width $9$:
- $2+2+2+3$
- $3+3+3$
- $2+3+2+2$
etc.
For each row, record the crack positions between bricks.
Example:
$$2+3+2+2$$
has cumulative sums
$$2,5,7,9$$
Ignoring the wall edge at $9$, the crack set is
$${2,5,7}$$
Two rows are compatible iff their crack sets are disjoint.
Step 2 — Number of possible rows
Let $R(w)$ be the number of rows of width $w$.
Then
$$R(w)=R(w-2)+R(w-3)$$
with:
$$R(0)=1,\quad R(1)=0,\quad R(2)=1,\quad R(3)=1$$
For $w=32$, this yields:
$$R(32)=3329$$
So there are only 3329 row types — small enough for graph methods.
Step 3 — Compatibility graph
Create a graph:
- each node = one row pattern,
- edge between nodes if no cracks align.
If row $i$ is compatible with row $j$, then they may be stacked consecutively.
We now want the number of height-10 stacks.
This is equivalent to counting walks of length $9$ in the compatibility graph.
Step 4 — Dynamic programming
Let:
$$dp_k(i)$$
be the number of crack-free walls of height $k$ ending with row $i$.
Initialize:
$$dp_1(i)=1$$
Then:
$$dp_{k+1}(j)=\sum_{i\sim j} dp_k(i)$$
where $i\sim j$ means compatible.
Finally:
$$W(32,10)=\sum_i dp_{10}(i)$$
Python implementation
from collections import defaultdict
WIDTH = 32
HEIGHT = 10
# ---------------------------------------------------------
# Generate all possible rows
# Each row is represented by a tuple of crack positions
# ---------------------------------------------------------
rows = []
def build(pos, cracks):
"""
Recursively build rows of total width WIDTH.
pos = current filled width
cracks = crack positions so far
"""
if pos == WIDTH:
rows.append(tuple(cracks))
return
# place a 2-brick
if pos + 2 <= WIDTH:
new_pos = pos + 2
build(
new_pos,
cracks + ([new_pos] if new_pos < WIDTH else [])
)
# place a 3-brick
if pos + 3 <= WIDTH:
new_pos = pos + 3
build(
new_pos,
cracks + ([new_pos] if new_pos < WIDTH else [])
)
build(0, [])
# ---------------------------------------------------------
# Build compatibility graph
# Two rows are compatible if they share no cracks
# ---------------------------------------------------------
n = len(rows)
compat = [[] for _ in range(n)]
crack_sets = [set(r) for r in rows]
for i in range(n):
for j in range(i + 1, n):
if crack_sets[i].isdisjoint(crack_sets[j]):
compat[i].append(j)
compat[j].append(i)
# ---------------------------------------------------------
# DP over wall height
# dp[i] = number of ways ending with row i
# ---------------------------------------------------------
dp = [1] * n # height = 1
for _ in range(HEIGHT - 1):
new_dp = [0] * n
for i in range(n):
for j in compat[i]:
new_dp[j] += dp[i]
dp = new_dp
answer = sum(dp)
print(answer)
Code walkthrough
Row generation
The recursive function:
build(pos, cracks)
tries adding either:
- a brick of width 2,
- or a brick of width 3.
Whenever we finish exactly at width 32, we store the crack positions.
Example:
2 + 3 + 2 + 2
produces:
(2, 5, 7)
Compatibility test
We convert each crack tuple into a set.
Two rows are compatible if:
setA.isdisjoint(setB)
meaning no cracks coincide.
Dynamic programming
Initially every row can be the first layer:
dp = [1] * n
For each additional layer:
new_dp[j] += dp[i]
whenever rows $i$ and $j$ are compatible.
After 10 layers, summing all possibilities gives the answer.
Verification on the small example
For the example in the problem:
$$W(9,3)=8$$
Changing:
WIDTH = 9
HEIGHT = 3
the program returns:
8
matching the statement.
Final verification
- Number of row states: $3329$, computationally reasonable.
- Compatibility graph is sparse.
- DP counts all valid height-10 stacks exactly once.
- The known published Project Euler value matches the computation.
Answer: 806844323190414