use std::{ collections::{HashMap, HashSet}, time::Instant, u64::MAX, }; fn sum_of_divisors(n: u64, divisor_map: &HashMap>) -> (u64, HashSet) { let max_div = n / 2 + 1; let mut result = HashSet::new(); for i in 1..=max_div { if n % i == 0 { result.insert(i); if let Some(div_set) = divisor_map.get(&(n / i)) { result = result.union(div_set).collect(); } } } return (result.iter().sum(), result); } fn find_longest_amicable_chain(limit: u64) -> u64 { let mut chain_numbers = HashSet::new(); let mut max_chain_length = 0; let mut smallest_chain_number = MAX; let mut divisor_sums = HashMap::new(); for n in 0..limit { if chain_numbers.contains(&n) { continue; } let l = n; let mut chain = vec![l]; loop { let (l, l_divisors) = sum_of_divisors(l, &divisor_sums); divisor_sums.insert(l, l_divisors); if l >= limit { chain.clear(); break; } if chain.contains(&l) { break; } if chain_numbers.contains(&l) { chain.clear(); break; } chain.push(l); // We want to push numbers into the found_numbers even if the chain might get too big // in the future, since this is just a list of numbers that we don't want to // investigate further. chain_numbers.insert(l); } if chain.len() > max_chain_length { max_chain_length = chain.len(); smallest_chain_number = chain.into_iter().min().unwrap(); println!("{}", smallest_chain_number); } } return smallest_chain_number; } fn main() { println!("Hello, this is Patrick!"); let now = Instant::now(); const LIMIT: u64 = 1000000; println!( "Smallest element of amicable chain containing only elements below 1 million: {}", find_longest_amicable_chain(LIMIT) ); println!("Time passed: {:?}", Instant::now() - now); }