Amicable chains
The proper divisors of a number are all the divisors excluding the number itself. For example, the proper divisors of are , , , , and . As the sum of these divisors is equal to , we call it a perfect number.
Interestingly the sum of the proper divisors of is and the sum of the proper divisors of is , forming a chain of two numbers. For this reason, and are called an amicable pair.
Perhaps less well known are longer chains. For example, starting with , we form a chain of five numbers:
Since this chain returns to its starting point, it is called an amicable chain.
Find the smallest member of the longest amicable chain with no element exceeding one million.
Implementations
#include <iostream>#include <vector>#include <algorithm>#include <set>
const int MAX = 1000000;
std::vector<int> sum_div(MAX + 1, 0);
void compute_sum_div() { for (int i = 1; i <= MAX; ++i) { for (int j = i * 2; j <= MAX; j += i) { sum_div[j] += i; } }}
long long amicable_chains() { compute_sum_div(); int max_length = 0; int min_member = MAX; std::vector<bool> visited(MAX + 1, false);
for (int i = 2; i <= MAX; ++i) { if (visited[i] || sum_div[i] > MAX) continue;
std::vector<int> chain; std::set<int> chain_set; int current = i;
while (current <= MAX && sum_div[current] != current && chain_set.find(current) == chain_set.end()) { chain.push_back(current); chain_set.insert(current); current = sum_div[current]; }
// Check if we found a cycle (current is already in chain) if (chain_set.find(current) != chain_set.end() && chain.size() > 1) { // Find where the cycle starts int cycle_start = -1; for (int j = 0; j < (int)chain.size(); ++j) { if (chain[j] == current) { cycle_start = j; break; } } int cycle_length = chain.size() - cycle_start;
if (cycle_length > max_length) { max_length = cycle_length; // Find smallest member in the cycle int smallest = MAX; for (size_t j = cycle_start; j < chain.size(); ++j) { if (chain[j] < smallest) smallest = chain[j]; visited[chain[j]] = true; // Mark cycle numbers as visited } min_member = smallest; } } }
return min_member;}Solution Notes
Mathematical Background
Amicable chains are sequences where each number is the sum of proper divisors of the previous. A chain forms a cycle when it returns to a starting point. The problem seeks the longest such chain below 1,000,000 and its smallest member.
Algorithm Analysis
Precompute sum of proper divisors for all numbers up to limit. Traverse chains from each unvisited number, using visited array to avoid redundancy and detecting cycles when encountering previously seen numbers in current chain.
Performance
Varies by language: ~500ms in C++/Go/Java/JavaScript, ~2s in Python, ~5s in Rust due to different optimization levels.
Key Insights
- Efficient divisor sum precomputation using sieve-like method
- Cycle detection prevents infinite loops and identifies valid chains
- Visited array ensures each number processed only once
Educational Value
Demonstrates graph traversal in number theory, cycle detection algorithms, and optimization of computational number theory problems across multiple programming paradigms.
Problem #95 is taken from Project Euler and licensed under CC BY-NC-SA 4.0.