85 lines
2.1 KiB
Rust
85 lines
2.1 KiB
Rust
use std::{
|
|
collections::{HashMap, HashSet},
|
|
time::Instant,
|
|
u64::MAX,
|
|
};
|
|
|
|
fn sum_of_divisors(n: u64, divisor_map: &HashMap<u64, HashSet<u64>>) -> (u64, HashSet<u64>) {
|
|
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);
|
|
}
|