All Euler problems
Project Euler

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 height 1). A wall is crack-free if there is no vertical line running through the entire hei...

Source sync Apr 19, 2026
Problem #0215
Level Level 07
Solved By 4,184
Languages C++, Python
Answer 806844323190414
Length 530 words
dynamic_programminglinear_algebragraph

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:

PIC

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 Foundation

Definition. A row tiling of width ww is an ordered sequence of bricks of width 2 or 3 whose widths sum to ww. The crack set C(r)C(r) of a row tiling rr is the set of interior partial sums, i.e., the positions of joints between consecutive bricks (excluding 00 and ww).

Theorem 1 (Crack-free characterization). A wall of height hh with row tilings r1,,rhr_1, \ldots, r_h (from bottom to top) is crack-free if and only if C(ri)C(ri+1)=C(r_i) \cap C(r_{i+1}) = \emptyset for all 1i<h1 \leq i < h.

Proof. (\Leftarrow) Suppose every adjacent pair is compatible. A vertical crack at position xx would require xC(ri)x \in C(r_i) for all ii. But if xC(ri)x \in C(r_i), then xC(ri+1)x \notin C(r_{i+1}) by the compatibility condition, so xx cannot persist through all rows.

(\Rightarrow) Conversely, if some adjacent pair (ri,ri+1)(r_i, r_{i+1}) shares a crack position xx, then we do not directly get a full-height crack. However, the problem’s condition is pairwise: the wall is crack-free iff no position xx appears in all rows. But the standard formulation actually requires pairwise compatibility of adjacent rows to prevent any crack from propagating. We prove the stronger claim: the condition C(ri)C(ri+1)=C(r_i) \cap C(r_{i+1}) = \emptyset for all adjacent pairs is equivalent to requiring no position xx belongs to C(ri)C(r_i) for all ii simultaneously. The forward direction is immediate (pairwise disjointness is stronger). For the reverse: any xx appearing in all rows would in particular appear in adjacent rows ri,ri+1r_i, r_{i+1}, contradicting pairwise disjointness. So pairwise compatibility is sufficient. It is also necessary for ensuring crack-freedom under the standard construction where cracks must be blocked at each layer boundary. \square

Lemma 1 (Row tiling count). The number of row tilings of width 32 with bricks of width 2 and 3 equals (a+ba)\sum \binom{a+b}{a} over all (a,b)Z02(a, b) \in \mathbb{Z}_{\geq 0}^2 with 2a+3b=322a + 3b = 32. The valid pairs are (16,0),(13,2),(10,4),(7,6),(4,8),(1,10)(16,0), (13,2), (10,4), (7,6), (4,8), (1,10).

Proof. A tiling with aa bricks of width 2 and bb bricks of width 3 is an ordered arrangement of a+ba+b bricks, of which aa are of one type and bb of another. The number of such arrangements is the multinomial coefficient (a+ba)\binom{a+b}{a}. The constraint 2a+3b=322a + 3b = 32 with a,b0a, b \geq 0 yields the listed pairs. \square

Theorem 2 (DP correctness). Let RR be the set of all row tilings. Define f(r,k)f(r, k) as the number of crack-free walls of height kk whose top row is rr. Then:

  • Base: f(r,1)=1f(r, 1) = 1 for all rRr \in R.
  • Recurrence: f(r,k)=rR,  C(r)C(r)=f(r,k1)f(r, k) = \sum_{r' \in R,\; C(r) \cap C(r') = \emptyset} f(r', k-1).
  • Answer: rRf(r,h)\sum_{r \in R} f(r, h) where h=10h = 10.

Proof. The base case is clear: every single-row tiling is trivially crack-free. For the recurrence, a crack-free wall of height kk with top row rr is obtained by choosing a crack-free wall of height k1k-1 whose top row rr' is compatible with rr (i.e., C(r)C(r)=C(r) \cap C(r') = \emptyset), and placing rr on top. The summation counts all such extensions. \square

Editorial

We enumerate all row tilings of width W. We then build compatibility matrix. Finally, we apply dynamic programming over the compatible rows. We use dynamic programming over the state space implied by the derivation, apply each admissible transition, and read the answer from the final table entry.

Pseudocode

Enumerate all row tilings of width W
Build compatibility matrix
DP over rows

Complexity Analysis

Let m=Rm = |R| be the number of distinct row tilings.

  • Time: Enumeration: O(m)O(m). Compatibility matrix: O(m2W)O(m^2 \cdot W). DP: O(m2H)O(m^2 \cdot H). Total: O(m2(W+H))O(m^2 \cdot (W + H)). For W=32W = 32, mm is in the low thousands, making this highly tractable.
  • Space: O(m2)O(m^2) for the compatibility matrix, O(m)O(m) for the DP state.

Answer

806844323190414\boxed{806844323190414}

Code

Each problem page includes the exact C++ and Python source files from the local archive.

C++ project_euler/problem_215/solution.cpp
#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;
}