Cyclical Figurate Numbers
Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers and are generated by the following formulae:
| Triangle | | | | | | Square | | | | | | Pentagonal | | | | | | Hexagonal | | | | | | Heptagonal | | | | | | Octagonal | | | | |
The ordered set of three -digit numbers: , , , has three interesting properties.
-
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).
-
Each polygonal type: triangle (), square (), and pentagonal (), is represented by a different number in the set.
-
This is the only set of -digit numbers with this property.
Find the sum of the only ordered set of six cyclic -digit numbers for which each polygonal type: triangle, square, pentagonal, hexagonal, heptagonal, and octagonal, is represented by a different number in the set.
Implementations
#include <iostream>#include <vector>#include <set>#include <functional>
int cyclical_figurate_numbers() { std::vector<std::vector<int>> polys(9);
auto gen_poly = [&](int type, auto formula) { for (int n = 1; ; ++n) { int num = formula(n); if (num >= 10000) break; if (num >= 1000) polys[type].push_back(num); } };
gen_poly(3, [](int n){ return n*(n+1)/2; }); gen_poly(4, [](int n){ return n*n; }); gen_poly(5, [](int n){ return n*(3*n-1)/2; }); gen_poly(6, [](int n){ return n*(2*n-1); }); gen_poly(7, [](int n){ return n*(5*n-3)/2; }); gen_poly(8, [](int n){ return n*(3*n-2); });
std::vector<std::vector<std::vector<int>>> by_prefix(9); for (int t = 3; t <= 8; ++t) { by_prefix[t].resize(100); for (int num : polys[t]) { int prefix = num / 100; by_prefix[t][prefix].push_back(num); } }
std::function<bool(std::vector<int>&, std::set<int>&, int)> find_cycle = [&](std::vector<int>& current, std::set<int>& used_types, int start_suffix) -> bool { if (current.size() == 6) { int last = current.back() % 100; int first = current[0] / 100; return last == first; }
int next_prefix = current.back() % 100; for (int t = 3; t <= 8; ++t) { if (used_types.count(t)) continue; for (int num : by_prefix[t][next_prefix]) { current.push_back(num); used_types.insert(t); if (find_cycle(current, used_types, start_suffix)) return true; used_types.erase(t); current.pop_back(); } } return false; };
std::vector<int> current; std::set<int> used_types;
for (int t = 3; t <= 8; ++t) { for (int num : polys[t]) { current = {num}; used_types = {t}; if (find_cycle(current, used_types, num / 100)) { int sum = 0; for (int n : current) sum += n; return sum; } } }
return -1;}
#if ! defined UNITTEST_MODEint main(int argc, char const *argv[]) { std::cout << cyclical_figurate_numbers() << std::endl;}#endifSolution Notes
Mathematical Background
This problem involves finding cyclic sets of figurate numbers where each type is represented exactly once, and the numbers form a cycle based on their last two and first two digits.
Algorithm Analysis
Generate all 4-digit polygonal numbers for each type, then use backtracking to find a cycle of six numbers, each of different types, where the last two digits of one match the first two of the next.
Performance Analysis
- Time Complexity: O(1) - fixed small search space
- Space Complexity: O(1) - small data structures
- Execution Time: Fast, backtracking finds solution quickly
- Scalability: Not applicable, fixed problem size
Key Insights
- Prefix maps enable efficient lookup of numbers with matching prefixes
- Backtracking with early termination finds the unique solution
- The solution sum is 28684
Educational Value
This problem teaches:
- Combinatorial search and backtracking
- Data structure optimization for prefix matching
- Working with polygonal number sequences
- Cycle detection in permutations