All Euler problems
Project Euler

Cyclical Figurate Numbers

Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers generated by: | Type | Formula | Sequence | |------|---------|----------| | Triangle...

Source sync Apr 19, 2026
Problem #0061
Level Level 02
Solved By 29,194
Languages C++, Python
Answer 28684
Length 692 words
searchmodular_arithmeticgraph

Problem Statement

This archive keeps the full statement, math, and original media on the page.

Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers and are generated by the following formulae:

Triangle$P_{3, n} = n(n + 1)/2$$1, 3, 6, 10, 15, \ldots$
Square$P{4, n} = n^2$$1, 4, 9, 25, \ldots$
Pentagonal$P_{5, n} = n(3n - 1)/2$$1, 5, 12, 22, 35, \ldots$
Henxagonal$P_{6, n} = n(2n - 1)/2$$1, 6, 15, 28, 45, \ldots$
Heptagonal$P_{7, n} = n(5n - 3)/2$$1, 7, 18, 34, 55, \ldots$
Octangonal$P_{8, n} = n(3n - 2)$$1, 8, 21, 40, 65, \ldots$

The ordered set of three $4$-digit numbers: $8128$, $2882$, $8281$, has three interesting properties.

  1. The set is cyclic, in that the last two digits of each number is the first two digits of the next number (including the last number with the first).

  2. Each polygonal type: triangle ($P_{3,127}=8128$), square ($P_{4,91}=8281$), and pentagonal ($P_{5,44}=2882$), is represented by a different number in the set.

  3. This is the only set of $4$-digit numbers with this property.

Find the sum of the only ordered set of six cyclic $4$-digit numbers for which each polygonal type: triangle, square, pentagonal, hexagonal, heptagonal, and octagonal, is represented by a different number in the set.

Problem 61: Cyclical Figurate Numbers

Mathematical Foundation

Definition 1. The ss-gonal number of order nn is defined as

P(s,n)=n[(s2)n(s4)]2,s3,  n1.P(s, n) = \frac{n\bigl[(s-2)n - (s-4)\bigr]}{2}, \quad s \ge 3, \; n \ge 1.

Theorem 1 (Closed form for polygonal numbers). The formula in Definition 1 satisfies P(s,1)=1P(s,1) = 1 for all s3s \ge 3, and the recurrence P(s,n)P(s,n1)=(s2)(n1)+1P(s,n) - P(s,n-1) = (s-2)(n-1) + 1 for n2n \ge 2.

Proof. Verification of the initial condition: P(s,1)=1[(s2)(s4)]2=22=1P(s,1) = \frac{1 \cdot [(s-2) - (s-4)]}{2} = \frac{2}{2} = 1. For the recurrence, compute

P(s,n)P(s,n1)=(s2)[n2(n1)2](s4)[n(n1)]2=(s2)(2n1)(s4)2.P(s,n) - P(s,n-1) = \frac{(s-2)[n^2 - (n-1)^2] - (s-4)[n - (n-1)]}{2} = \frac{(s-2)(2n-1) - (s-4)}{2}.

Simplifying: 2(s2)n(s2)(s4)2=2(s2)n2s+62=(s2)ns+3=(s2)(n1)+1\frac{2(s-2)n - (s-2) - (s-4)}{2} = \frac{2(s-2)n - 2s + 6}{2} = (s-2)n - s + 3 = (s-2)(n-1) + 1. This matches the defining property that consecutive differences of ss-gonal numbers form an arithmetic progression with common difference s2s-2. \square

Lemma 1 (Index bounds for 4-digit polygonal numbers). For each s{3,4,5,6,7,8}s \in \{3,4,5,6,7,8\}, the indices nn producing 4-digit values 1000P(s,n)99991000 \le P(s,n) \le 9999 form a contiguous range [nmin(s),nmax(s)][n_{\min}(s), n_{\max}(s)]:

ssnminn_{\min}nmaxn_{\max}Count
34514096
4329968
5268156
6237048
7216343
8195840

Proof. Since P(s,n)P(s,n) is a strictly increasing function of nn for n1n \ge 1 (each successive difference (s2)(n1)+1>0(s-2)(n-1)+1 > 0), the set {n:1000P(s,n)9999}\{n : 1000 \le P(s,n) \le 9999\} is a contiguous integer interval. The endpoints are obtained by solving the quadratic P(s,n)=MP(s,n) = M:

n=(s4)+(s4)2+8(s2)M2(s2),n = \frac{(s-4) + \sqrt{(s-4)^2 + 8(s-2)M}}{2(s-2)},

taking the positive root. Then nmin(s)=n(M=1000)n_{\min}(s) = \lceil n(M=1000) \rceil and nmax(s)=n(M=9999)n_{\max}(s) = \lfloor n(M=9999) \rfloor. Direct evaluation confirms the table entries. \square

Definition 2 (Cyclic linking). A 4-digit number NN links to another 4-digit number NN' if Nmod100=N/100N \bmod 100 = \lfloor N'/100 \rfloor, i.e., the last two digits of NN equal the first two digits of NN'. Both the suffix Nmod100N \bmod 100 and the prefix N/100\lfloor N'/100 \rfloor must lie in {10,11,,99}\{10, 11, \ldots, 99\} for meaningful two-digit linking.

Theorem 2 (Graph formulation). Define a directed labeled multigraph G=(V,E)G = (V, E) where:

  • V={10,11,,99}V = \{10, 11, \ldots, 99\} (the 90 possible two-digit prefixes/suffixes),
  • For each 4-digit polygonal number NN of type ss with N/100=p\lfloor N/100 \rfloor = p and Nmod100=q10N \bmod 100 = q \ge 10, include the directed edge (p,q)(p, q) with label ss and weight NN.

Then a valid solution to the problem corresponds to a directed 6-cycle v1v2v6v1v_1 \to v_2 \to \cdots \to v_6 \to v_1 in GG whose edges carry all six distinct labels {3,4,5,6,7,8}\{3,4,5,6,7,8\}.

Proof. Let (N1,N2,,N6)(N_1, N_2, \ldots, N_6) be a valid cyclic set. Define vi=Ni/100v_i = \lfloor N_i / 100 \rfloor. The cyclic condition Nimod100=Ni+1/100=vi+1N_i \bmod 100 = \lfloor N_{i+1}/100 \rfloor = v_{i+1} (indices modulo 6) means each NiN_i corresponds to the edge (vi,vi+1)(v_i, v_{i+1}). Each NiN_i has a unique polygonal type, giving six distinct edge labels. Conversely, any such 6-cycle in GG with all six labels yields a valid solution by reading off the edge weights. \square

Theorem 3 (Uniqueness). The solution is unique up to cyclic rotation.

Proof. By exhaustive depth-first search over GG with backtracking, starting from every possible initial edge and exploring all label-valid extensions, exactly one equivalence class of 6-cycles (under cyclic rotation) is found. The completeness of depth-first search with backtracking guarantees that no valid cycle is missed. \square

Editorial

We first enumerate all 4-digit polygonal numbers of types 33 through 88 and keep only those whose last two digits form a valid two-digit suffix. Each remaining number is then treated as a labeled link from its first two digits to its last two digits. Starting from every possible value, we perform a depth-first backtracking search that extends the chain only through matching suffix-prefix links and polygonal types that have not yet been used. A candidate is accepted only when it contains six values, uses all six types exactly once, and closes back to its starting prefix.

Pseudocode

Generate the 4-digit polygonal numbers of each required type.
Ignore any value whose final two digits do not form a valid link.

Organize the remaining values by polygonal type and by their first two digits.

For each possible starting value:
    begin a chain containing only that value
    mark its polygonal type as used
    try to extend the chain recursively

During the recursive search:
    if the chain already contains six values:
        accept it only when the current suffix matches the opening prefix

    otherwise, for each polygonal type not yet used:
        inspect the values of that type whose prefix matches the current suffix
        extend the chain by each such value in turn

Return the sum of the first chain that closes cyclically.

Complexity Analysis

Time: Let E=sEs351E = \sum_{s} |E_s| \le 351 be the total number of valid edges. The DFS explores at most d=15Bd\prod_{d=1}^{5} B_d paths from each starting edge, where BdB_d is the branching factor at depth dd. Since the label-uniqueness constraint eliminates at least one type per level and the average out-degree per vertex is E/V4E/|V| \approx 4, the effective search space is small. The overall worst-case bound is O(E(E/V)5)O(E \cdot (E/|V|)^5), which evaluates to a constant for this problem size.

Space: O(E)O(E) for the adjacency lists, plus O(6)O(6) for the DFS recursion stack. Total: O(E)O(E).

Answer

28684\boxed{28684}

Code

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

C++ project_euler/problem_061/solution.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    // P(s,n) = n * ((s-2)*n - (s-4)) / 2
    auto polygonal = [](int s, int n) -> int {
        return n * ((s - 2) * n - (s - 4)) / 2;
    };

    // Generate all 4-digit polygonal numbers for types 3..8
    vector<vector<int>> poly(6);
    for (int s = 3; s <= 8; s++) {
        for (int n = 1; ; n++) {
            int val = polygonal(s, n);
            if (val >= 10000) break;
            if (val >= 1000 && val % 100 >= 10)
                poly[s - 3].push_back(val);
        }
    }

    // Build adjacency: by_prefix[type][prefix] = list of (suffix, value)
    vector<unordered_map<int, vector<pair<int,int>>>> by_prefix(6);
    for (int t = 0; t < 6; t++)
        for (int v : poly[t]) {
            int p = v / 100, s = v % 100;
            by_prefix[t][p].push_back({s, v});
        }

    // DFS to find 6-cycle using all six types
    int answer = 0;
    int chain[6];

    function<void(int, int, int, int)> dfs =
        [&](int depth, int used_mask, int cur_suffix, int start_prefix) {
        if (answer) return;
        if (depth == 6) {
            if (cur_suffix == start_prefix) {
                int sum = 0;
                for (int i = 0; i < 6; i++) sum += chain[i];
                answer = sum;
            }
            return;
        }
        for (int t = 0; t < 6; t++) {
            if (used_mask & (1 << t)) continue;
            auto it = by_prefix[t].find(cur_suffix);
            if (it == by_prefix[t].end()) continue;
            for (auto& [suf, val] : it->second) {
                chain[depth] = val;
                dfs(depth + 1, used_mask | (1 << t), suf, start_prefix);
                if (answer) return;
            }
        }
    };

    for (int t = 0; t < 6 && !answer; t++)
        for (int v : poly[t]) {
            int p = v / 100, s = v % 100;
            chain[0] = v;
            dfs(1, 1 << t, s, p);
            if (answer) break;
        }

    cout << answer << endl;
    return 0;
}