Tim Varley Logo
Tim Varley Principal AI Engineer and Tech Leader
Problem #74 easy

Digit Factorial Chains

The number 145145 is well known for the property that the sum of the factorial of its digits is equal to 145145: 1!+4!+5!=1+24+120=145.1! + 4! + 5! = 1 + 24 + 120 = 145.

Perhaps less well known is 169169, in that it produces the longest chain of numbers that link back to 169169; it turns out that there are only three such loops that exist:

&169 \to 363601 \to 1454 \to 169\\ &871 \to 45361 \to 871\\ &872 \to 45362 \to 872 \end{align}$$ It is not difficult to prove that EVERY starting number will eventually get stuck in a loop. For example, $$\begin{align} &69 \to 363600 \to 1454 \to 169 \to 363601 (\to 1454)\\ &78 \to 45360 \to 871 \to 45361 (\to 871)\\ &540 \to 145 (\to 145) \end{align}$$ Starting with $69$ produces a chain of five non-repeating terms, but the longest non-repeating chain with a starting number below one million is sixty terms. How many chains, with a starting number below one million, contain exactly sixty non-repeating terms?
View on Project Euler

Implementations

cpp
#include <iostream>
#include <set>
int fact[10] = {1,1,2,6,24,120,720,5040,40320,362880};
int digit_fact_sum(int n)
{
int sum = 0;
while(n > 0){
sum += fact[n % 10];
n /= 10;
}
return sum;
}
int digit_factorial_chains()
{
int count = 0;
for(int i=1; i<1000000; i++){
std::set<int> seen;
int n = i;
while(seen.find(n) == seen.end()){
seen.insert(n);
n = digit_fact_sum(n);
}
if(seen.size() == 60){
count++;
}
}
return count;
}
#if ! defined UNITTEST_MODE
int main(int argc, char const *argv[])
{
std::cout << "Answer: " << digit_factorial_chains() << std::endl;
}
#endif // #if ! defined UNITTEST_MODE
View on GitHub
O(N) time, O(1) space per chain (set tracks seen numbers)
tvarley.github.io/src/content/euler/problem-074.md