Crack-free Walls
Consider building a wall that is 32 units wide and 10 units tall using bricks of width 2 and width 3, all of height 1. A wall is crack-free if the gaps between horizontally adjacent bricks never li...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Consider the problem of building a wall out of \(2 \times 1\) and \(3 \times 1\) bricks (\(\text {horizontal} \times \text {vertical}\) dimensions) such that, for extra strength, the gaps between horizontally-adjacent bricks never line up in consecutive layers, i.e. never form a "running crack".
For example, the following \(9 \times 3\) wall is not acceptable due to the running crack shown in red:

There are eight ways of forming a crack-free \(9 \times 3\) wall, written \(W(9,3) = 8\).
Calculate \(W(32,10)\).
Problem 215: Crack-free Walls
Mathematical Development
Definition. A row tiling of width is an ordered sequence of bricks of width 2 or 3 whose widths sum to . The crack set of a row tiling is the set of interior partial sums, namely the joint positions between consecutive bricks, excluding 0 and .
Theorem 1 (Consecutive-layer characterization). A wall with rows is crack-free if and only if
Proof. This is exactly the condition stated in the problem: no crack position may line up in two consecutive layers. A position lines up between rows and precisely when .
Lemma 1 (Row tiling count). The number of row tilings of width 32 with bricks of width 2 and 3 equals
over all satisfying . The valid pairs are
Proof. A tiling with bricks of width 2 and bricks of width 3 is an ordering of objects with identical 2-bricks and identical 3-bricks. The number of such orderings is . The width equation gives the listed pairs.
Theorem 2 (Dynamic programming on the compatibility graph). Let be the set of all row tilings. Define as the number of crack-free walls of height whose top row is . Then
- Base case: for all .
- Recurrence:
- Answer:
Proof. A valid wall of height ending in row is obtained by taking a valid wall of height ending in some compatible row and placing above it. Every valid wall arises uniquely in this way.
Editorial
The geometry disappears once each row is represented by its crack positions. A row is compatible with another row exactly when their crack sets are disjoint, so the wall problem becomes a path-counting problem in a finite compatibility graph whose vertices are the possible row tilings.
That graph is small enough to build explicitly. After generating all width-32 rows, precompute which pairs are compatible. Then dynamic programming over the wall height counts how many ways there are to end with each possible top row. Summing those counts after 10 layers gives the total number of crack-free walls.
Pseudocode
Generate every row tiling of width 32.
For each row, store the set or bitmask of its crack positions.
Build the compatibility list:
row i is adjacent to row j
if their crack sets are disjoint.
Set dp[i] = 1 for every row i, representing walls of height 1.
Repeat 9 times:
Create a new array next filled with 0.
For each row i:
For each compatible predecessor j of row i:
next[i] += dp[j]
Replace dp by next.
Return the sum of all entries of dp.
Complexity Analysis
Let be the number of width-32 row tilings.
- Time: to build compatibility, then for the height DP.
- Space: for the compatibility graph and for the DP arrays.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
int W = 32;
int H = 10;
vector<vector<int>> rows; // each row is a set of crack positions
void generate(int pos, vector<int>& cracks) {
if (pos == W) {
rows.push_back(cracks);
return;
}
// Try placing a 2-brick
if (pos + 2 <= W) {
if (pos + 2 < W) cracks.push_back(pos + 2);
generate(pos + 2, cracks);
if (pos + 2 < W) cracks.pop_back();
}
// Try placing a 3-brick
if (pos + 3 <= W) {
if (pos + 3 < W) cracks.push_back(pos + 3);
generate(pos + 3, cracks);
if (pos + 3 < W) cracks.pop_back();
}
}
int main() {
vector<int> cracks;
generate(0, cracks);
int m = rows.size();
// Convert crack positions to bitmask for fast compatibility check
vector<unsigned int> mask(m, 0);
for (int i = 0; i < m; i++) {
for (int c : rows[i]) {
mask[i] |= (1u << c);
}
}
// Build compatibility list
vector<vector<int>> compat(m);
for (int i = 0; i < m; i++) {
for (int j = 0; j < m; j++) {
if ((mask[i] & mask[j]) == 0) {
compat[i].push_back(j);
}
}
}
// DP
vector<long long> dp(m, 1); // height 1: each row has 1 way
for (int h = 2; h <= H; h++) {
vector<long long> ndp(m, 0);
for (int i = 0; i < m; i++) {
for (int j : compat[i]) {
ndp[i] += dp[j];
}
}
dp = ndp;
}
long long answer = 0;
for (int i = 0; i < m; i++) {
answer += dp[i];
}
cout << answer << endl;
return 0;
}
def solve():
W = 32
H = 10
# Generate all row tilings as sets of crack positions
rows = []
def generate(pos, cracks):
if pos == W:
rows.append(frozenset(cracks))
return
# Try 2-brick
if pos + 2 <= W:
new_cracks = cracks + ([pos + 2] if pos + 2 < W else [])
generate(pos + 2, new_cracks)
# Try 3-brick
if pos + 3 <= W:
new_cracks = cracks + ([pos + 3] if pos + 3 < W else [])
generate(pos + 3, new_cracks)
generate(0, [])
m = len(rows)
# Build compatibility: two rows are compatible if they share no crack position
compat = [[] for _ in range(m)]
for i in range(m):
for j in range(m):
if rows[i].isdisjoint(rows[j]):
compat[i].append(j)
# DP: dp[i] = number of walls of current height ending with row i
dp = [1] * m # height 1
for h in range(2, H + 1):
ndp = [0] * m
for i in range(m):
for j in compat[i]:
ndp[i] += dp[j]
dp = ndp
answer = sum(dp)
print(answer)
if __name__ == "__main__":
solve()