Merge remote-tracking branch 'refs/remotes/origin/main'
This commit is contained in:
+10
-8
@@ -96,18 +96,18 @@ where
|
|||||||
while !(self.unvisited_without_distance.is_empty()
|
while !(self.unvisited_without_distance.is_empty()
|
||||||
&& self.unvisited_with_distance.is_empty())
|
&& self.unvisited_with_distance.is_empty())
|
||||||
{
|
{
|
||||||
let coord = self.get_unvisited_coord_with_smallest_distance_from_start();
|
let to_visit = self.get_unvisited_coord_with_smallest_distance_from_start();
|
||||||
let neighbours = self.get_neighbours(&coord);
|
self.visit(to_visit);
|
||||||
let previous_distance = *self.matrix.get(coord).unwrap().get_distance().unwrap();
|
let neighbours = self.get_neighbours(&to_visit);
|
||||||
|
let previous_distance = *self.matrix.get(to_visit).unwrap().get_distance().unwrap();
|
||||||
for neighbour in neighbours {
|
for neighbour in neighbours {
|
||||||
self.update_neighbour(neighbour, coord, previous_distance);
|
self.update_neighbour(neighbour, to_visit, previous_distance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_unvisited_coord_with_smallest_distance_from_start(&mut self) -> Coordinate {
|
fn get_unvisited_coord_with_smallest_distance_from_start(&mut self) -> Coordinate {
|
||||||
let coord = self
|
self.unvisited_with_distance
|
||||||
.unvisited_with_distance
|
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|c| {
|
.filter_map(|c| {
|
||||||
let node = self.matrix.get(*c).unwrap();
|
let node = self.matrix.get(*c).unwrap();
|
||||||
@@ -115,9 +115,11 @@ where
|
|||||||
})
|
})
|
||||||
.reduce(|(c0, v0), (c1, v1)| if v0 < v1 { (c0, v0) } else { (c1, v1) })
|
.reduce(|(c0, v0), (c1, v1)| if v0 < v1 { (c0, v0) } else { (c1, v1) })
|
||||||
.map(|(c, _)| *c)
|
.map(|(c, _)| *c)
|
||||||
.unwrap_or(self.start);
|
.unwrap_or(self.start)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit(&mut self, coord: (usize, usize)) {
|
||||||
self.unvisited_with_distance.remove(&coord);
|
self.unvisited_with_distance.remove(&coord);
|
||||||
coord
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_neighbours(&self, coordinate: &Coordinate) -> Vec<Coordinate> {
|
fn get_neighbours(&self, coordinate: &Coordinate) -> Vec<Coordinate> {
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ use std::fs::File;
|
|||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::slice::Iter;
|
use std::slice::Iter;
|
||||||
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
use num::FromPrimitive;
|
use num::FromPrimitive;
|
||||||
use num::Num;
|
use num::Num;
|
||||||
use num::ToPrimitive;
|
use num::ToPrimitive;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Primes<T> {
|
pub struct Primes<T> {
|
||||||
vector: Vec<T>,
|
vector: Vec<T>,
|
||||||
set: HashSet<T>,
|
set: HashSet<T>,
|
||||||
@@ -110,6 +111,10 @@ where
|
|||||||
pub fn into_vec(self) -> Vec<T> {
|
pub fn into_vec(self) -> Vec<T> {
|
||||||
self.vector
|
self.vector
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_cloned_iter(&self) -> IntoIter<T> {
|
||||||
|
self.vector.clone().into_iter()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
+31
-25
@@ -13,39 +13,45 @@ fn main() {
|
|||||||
squbes.iterate();
|
squbes.iterate();
|
||||||
squbes.iterate();
|
squbes.iterate();
|
||||||
squbes.iterate();
|
squbes.iterate();
|
||||||
println!("{:?}", squbes.output());
|
println!("{:?}", squbes.get_output());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Squbes {
|
struct Squbes {
|
||||||
squbes: HashSet<u64>,
|
squbes: HashSet<u64>,
|
||||||
new_squbes: Vec<u64>,
|
primes: Primes<u64>,
|
||||||
primes: IntoIter<u64>,
|
primes_iter: IntoIter<u64>,
|
||||||
used_primes: Vec<u64>,
|
used_primes: Vec<u64>,
|
||||||
current_prime: u64,
|
current_prime: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Squbes {
|
impl Squbes {
|
||||||
pub fn new(max: u64) -> Self {
|
pub fn new(max: u64) -> Self {
|
||||||
let mut primes = Primes::get_between(2, max).into_vec().into_iter();
|
let primes = Primes::get_between(2, max);
|
||||||
let first = primes.next().unwrap();
|
let mut primes_iter = primes.to_cloned_iter();
|
||||||
let second = primes.next().unwrap();
|
let first = primes_iter.next().unwrap();
|
||||||
|
let second = primes_iter.next().unwrap();
|
||||||
Self {
|
Self {
|
||||||
squbes: HashSet::new(),
|
squbes: HashSet::new(),
|
||||||
new_squbes: vec![],
|
|
||||||
primes,
|
primes,
|
||||||
|
primes_iter,
|
||||||
used_primes: vec![first],
|
used_primes: vec![first],
|
||||||
current_prime: second,
|
current_prime: second,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iterate(&mut self) {
|
pub fn iterate(&mut self) {
|
||||||
self.calculate_squbes_with_current_prime();
|
let squbes = self.calculate_squbes_with_current_prime();
|
||||||
self.save_current_prime();
|
self.save_current_prime();
|
||||||
self.update_current_prime();
|
self.update_current_prime();
|
||||||
|
self.save_new_squbes();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn output(&self) -> Vec<u64> {
|
fn save_new_squbes(&mut self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_output(&self) -> Vec<u64> {
|
||||||
let mut result: Vec<_> = self.squbes.iter().copied().collect();
|
let mut result: Vec<_> = self.squbes.iter().copied().collect();
|
||||||
result.sort_unstable();
|
result.sort_unstable();
|
||||||
result
|
result
|
||||||
@@ -56,27 +62,27 @@ impl Squbes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_current_prime(&mut self) {
|
fn update_current_prime(&mut self) {
|
||||||
self.current_prime = self.primes.next().unwrap();
|
self.current_prime = self.primes_iter.next().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_squbes_with_current_prime(&mut self) {
|
fn calculate_squbes_with_current_prime(&mut self) -> Vec<u64> {
|
||||||
assert_ne!(self.current_prime, 0);
|
get_iterator_over_pairs_both_ways(&self.used_primes, self.current_prime)
|
||||||
let iter = self
|
.map(|(p, q)| Self::core(p, q))
|
||||||
.used_primes
|
.collect()
|
||||||
.iter()
|
|
||||||
.copied()
|
|
||||||
.zip([self.current_prime].into_iter().cycle())
|
|
||||||
.chain(
|
|
||||||
[self.current_prime]
|
|
||||||
.into_iter()
|
|
||||||
.cycle()
|
|
||||||
.zip(self.used_primes.iter().copied()),
|
|
||||||
)
|
|
||||||
.map(|(p, q)| Self::core(p, q));
|
|
||||||
self.new_squbes.extend(iter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn core(p: u64, q: u64) -> u64 {
|
fn core(p: u64, q: u64) -> u64 {
|
||||||
p.pow(2) * q.pow(3)
|
p.pow(2) * q.pow(3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_iterator_over_pairs_both_ways(
|
||||||
|
vec: &[u64],
|
||||||
|
value: u64,
|
||||||
|
) -> impl Iterator<Item = (u64, u64)> + '_ {
|
||||||
|
iterate_vec_and_scalar(vec, value).flat_map(|(x, y)| [(x, y), (y, x)].into_iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iterate_vec_and_scalar(vec: &[u64], value: u64) -> impl Iterator<Item = (u64, u64)> + '_ {
|
||||||
|
vec.iter().copied().zip([value].into_iter().cycle())
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "euler85"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
const TARGET: usize = 2_000_000;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut x = 1_000;
|
||||||
|
let mut y = 2;
|
||||||
|
|
||||||
|
let mut grid = Grid::new(x, y);
|
||||||
|
let mut number;
|
||||||
|
let mut best_grid = grid.clone();
|
||||||
|
let mut best_diff = 5_000_000;
|
||||||
|
loop {
|
||||||
|
number = grid.number_rectangles();
|
||||||
|
let diff = number.abs_diff(TARGET);
|
||||||
|
if diff < best_diff {
|
||||||
|
best_diff = diff;
|
||||||
|
best_grid = grid.clone();
|
||||||
|
}
|
||||||
|
if number < TARGET {
|
||||||
|
y += 1;
|
||||||
|
} else {
|
||||||
|
x -= 1;
|
||||||
|
}
|
||||||
|
if x == 1 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
grid = Grid::new(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
let area = best_grid.area();
|
||||||
|
println!("{area}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Grid {
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grid {
|
||||||
|
fn new(x: usize, y: usize) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn number_rectangles(&self) -> usize {
|
||||||
|
let mut result = 0;
|
||||||
|
|
||||||
|
for x in 1..=self.x {
|
||||||
|
for y in 1..=self.y {
|
||||||
|
result += self.fits(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fits(&self, x: usize, y: usize) -> usize {
|
||||||
|
let fits_in_x = self.x - (x - 1);
|
||||||
|
let fits_in_y = self.y - (y - 1);
|
||||||
|
fits_in_x * fits_in_y
|
||||||
|
}
|
||||||
|
|
||||||
|
fn area(&self) -> usize {
|
||||||
|
self.x * self.y
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "euler86"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = "fat"
|
||||||
|
debug = true
|
||||||
|
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
use std::f64::EPSILON;
|
||||||
|
|
||||||
|
const TARGET: u32 = 1_000_000;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut m = 1;
|
||||||
|
let mut distinct = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
println!("trying: {m}");
|
||||||
|
|
||||||
|
for x in 1..m + 1 {
|
||||||
|
for y in x..m + 1 {
|
||||||
|
let z = m;
|
||||||
|
let c = Cuboid::new(x, y, z);
|
||||||
|
if c.shortest_path_is_integer() {
|
||||||
|
distinct += 1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if distinct > TARGET {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("\n{m}");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Cuboid {
|
||||||
|
x: u32,
|
||||||
|
y: u32,
|
||||||
|
z: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cuboid {
|
||||||
|
fn new(x: u32, y: u32, z: u32) -> Self {
|
||||||
|
Self { x, y, z }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shortest_path_is_integer(&self) -> bool {
|
||||||
|
// because of the way we iterator over x, y and z, these are guaranteed to be in order
|
||||||
|
// and therefore produces the shortest path
|
||||||
|
let shortest_path = pythagorean(self.x + self.y, self.z);
|
||||||
|
|
||||||
|
is_integer(shortest_path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pythagorean(x: u32, y: u32) -> f64 {
|
||||||
|
((x.pow(2) + y.pow(2)) as f64).sqrt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_integer(result: f64) -> bool {
|
||||||
|
let rounded = result.round();
|
||||||
|
|
||||||
|
(result - rounded).abs() <= EPSILON
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "euler92"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = "fat"
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
const MAXIMUM: usize = 10_000_000;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut arrives_at_89 = 0;
|
||||||
|
|
||||||
|
for i in 1..MAXIMUM {
|
||||||
|
let mut number = i;
|
||||||
|
loop {
|
||||||
|
let sum: usize = number
|
||||||
|
.to_digits()
|
||||||
|
.into_iter()
|
||||||
|
.map(|d| d.pow(2) as usize)
|
||||||
|
.sum();
|
||||||
|
if sum == 89 {
|
||||||
|
arrives_at_89 += 1;
|
||||||
|
break;
|
||||||
|
} else if sum == 1 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
number = sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{arrives_at_89}");
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ToDigits {
|
||||||
|
fn to_digits(&self) -> Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToDigits for usize {
|
||||||
|
fn to_digits(&self) -> Vec<u8> {
|
||||||
|
self.to_string()
|
||||||
|
.chars()
|
||||||
|
.map(|c| c.to_digit(10).unwrap() as _)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "euler93"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "*"
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
type Num = f64;
|
||||||
|
type Quadruple = [Num; 4];
|
||||||
|
|
||||||
|
const ALL_DIGITS: [Num; 10] = [0., 1., 2., 3., 4., 5., 6., 7., 8., 9.];
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut digits_length = vec![];
|
||||||
|
|
||||||
|
for quadruple_vec in ALL_DIGITS.into_iter().permutations(4) {
|
||||||
|
let quadruple = vec_to_quadruple(quadruple_vec);
|
||||||
|
|
||||||
|
let digits = Digits(quadruple);
|
||||||
|
|
||||||
|
let permutations = digits.permutations();
|
||||||
|
|
||||||
|
let mut results: Vec<_> = permutations
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(find_integer_results)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
results.sort_unstable_by(|n1, n2| {
|
||||||
|
if n1 < n2 {
|
||||||
|
Ordering::Less
|
||||||
|
} else {
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = results
|
||||||
|
.into_iter()
|
||||||
|
.tuple_windows()
|
||||||
|
.filter(|(v0, v1)| (v1 - v0) > Num::EPSILON)
|
||||||
|
.map(|(n1, _)| n1) // TODO last number may be missing?
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
let length = number_consecutive_positive_integers(result);
|
||||||
|
|
||||||
|
digits_length.push((quadruple, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
digits_length.sort_unstable_by(|a, b| a.1.cmp(&b.1));
|
||||||
|
|
||||||
|
let mut result = digits_length.last().unwrap().0;
|
||||||
|
|
||||||
|
result.sort_by(Num::total_cmp);
|
||||||
|
|
||||||
|
let s: String = result
|
||||||
|
.into_iter()
|
||||||
|
.map(|d| char::from_digit(d as u32, 10).unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
println!("{s}");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn number_consecutive_positive_integers(result: Vec<f64>) -> usize {
|
||||||
|
let length = result.len();
|
||||||
|
|
||||||
|
result
|
||||||
|
.into_iter()
|
||||||
|
.tuple_windows()
|
||||||
|
.filter(|(a, b)| b - 1.5 > *a)
|
||||||
|
.map(|(a, _)| a.round() as usize)
|
||||||
|
.next()
|
||||||
|
.unwrap_or(length)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_integer_results(quadruple: Quadruple) -> Vec<Num> {
|
||||||
|
let [i0, i1, i2, i3] = quadruple;
|
||||||
|
|
||||||
|
let mut result = vec![];
|
||||||
|
|
||||||
|
for op1 in Operations::iter() {
|
||||||
|
for op2 in Operations::iter() {
|
||||||
|
for op3 in Operations::iter() {
|
||||||
|
let num = op3(op2(op1(i0, i1), i2), i3);
|
||||||
|
if num > 0. && is_integer(num) {
|
||||||
|
result.push(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_integer(num: Num) -> bool {
|
||||||
|
(num.round() - num).abs() <= Num::EPSILON
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Digits(Quadruple);
|
||||||
|
|
||||||
|
impl Digits {
|
||||||
|
fn permutations(&self) -> Vec<Quadruple> {
|
||||||
|
self.0
|
||||||
|
.into_iter()
|
||||||
|
.permutations(4)
|
||||||
|
.map(vec_to_quadruple)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vec_to_quadruple(v: Vec<f64>) -> Quadruple {
|
||||||
|
unsafe {
|
||||||
|
let i0 = *v.get_unchecked(0);
|
||||||
|
let i1 = *v.get_unchecked(1);
|
||||||
|
let i2 = *v.get_unchecked(2);
|
||||||
|
let i3 = *v.get_unchecked(3);
|
||||||
|
[i0, i1, i2, i3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Operations {
|
||||||
|
last: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for Operations {
|
||||||
|
type Item = Box<dyn Fn(Num, Num) -> Num>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.last += 1;
|
||||||
|
match self.last {
|
||||||
|
1 => Some(Box::new(|l, r| l + r)),
|
||||||
|
2 => Some(Box::new(|l, r| l - r)),
|
||||||
|
3 => Some(Box::new(|l, r| r - l)),
|
||||||
|
4 => Some(Box::new(|l, r| l * r)),
|
||||||
|
5 => Some(Box::new(|l, r| l / r)),
|
||||||
|
6 => Some(Box::new(|l, r| r / l)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operations {
|
||||||
|
fn iter() -> Self {
|
||||||
|
Self { last: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "euler94"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
f128 = "0.2.9"
|
||||||
|
num-traits = "0.2.15"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = "fat"
|
||||||
|
codegen-units = 1
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
type Num = usize;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut sum = 0;
|
||||||
|
|
||||||
|
let mut i = 5;
|
||||||
|
'outer: loop {
|
||||||
|
if i > 333_333_334 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let a = i;
|
||||||
|
|
||||||
|
if a % 2 == 0 {
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for c in [a - 1, a + 1] {
|
||||||
|
let t = Triangle::new(a, c);
|
||||||
|
|
||||||
|
if t.has_integer_area() {
|
||||||
|
println!("{:.10}, {:.10}", t.a, t.c);
|
||||||
|
sum += t.perimeter();
|
||||||
|
i = ((i as f64) * 3.59).trunc() as usize;
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{sum:.15}");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Triangle {
|
||||||
|
a: Num,
|
||||||
|
c: Num,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Triangle {
|
||||||
|
fn new(a: Num, c: Num) -> Self {
|
||||||
|
Self { a, c }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn perimeter(&self) -> Num {
|
||||||
|
2 * self.a + self.c
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_integer_area(&self) -> bool {
|
||||||
|
let h = 4 * self.a.pow(2) - self.c.pow(2);
|
||||||
|
let root = (h as f64).sqrt().trunc() as usize;
|
||||||
|
|
||||||
|
root * root == h
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "euler95"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
rstest = "0.17"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
debug = true
|
||||||
|
lto = "fat"
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
const MAX: usize = 1_000_000;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut chains = vec![];
|
||||||
|
|
||||||
|
let mut part_of_any_chain = HashSet::new();
|
||||||
|
|
||||||
|
for current in 1..MAX {
|
||||||
|
if part_of_any_chain.contains(¤t) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try_build_chain_from_number(MAX, current, &mut chains, &mut part_of_any_chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
chains.sort_by_key(|chain| chain.len());
|
||||||
|
|
||||||
|
let longest = chains.last().unwrap();
|
||||||
|
|
||||||
|
let smallest = longest.iter().min().unwrap().to_owned();
|
||||||
|
|
||||||
|
println!("{smallest}");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_proper_divisors(max: usize) -> Vec<Vec<usize>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_build_chain_from_number(
|
||||||
|
max: usize,
|
||||||
|
mut current: usize,
|
||||||
|
chains: &mut Vec<Vec<usize>>,
|
||||||
|
part_of_any_chain: &mut HashSet<usize>,
|
||||||
|
) {
|
||||||
|
let mut maybe_chain = vec![];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
maybe_chain.push(current);
|
||||||
|
|
||||||
|
let next: usize = get_proper_divisors(current).into_iter().sum();
|
||||||
|
|
||||||
|
if next > max || next == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if maybe_chain.contains(&next) {
|
||||||
|
if maybe_chain.len() > 1 && *maybe_chain.first().unwrap() == next {
|
||||||
|
for number in &maybe_chain {
|
||||||
|
part_of_any_chain.insert(*number);
|
||||||
|
}
|
||||||
|
println!("{}", maybe_chain.first().unwrap());
|
||||||
|
chains.push(maybe_chain);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_proper_divisors(x: usize) -> Vec<usize> {
|
||||||
|
let mut result = vec![1];
|
||||||
|
|
||||||
|
let limit = x / 2 + 1;
|
||||||
|
|
||||||
|
for i in 2..limit {
|
||||||
|
if result.contains(&i) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if x % i == 0 {
|
||||||
|
let div_1 = i;
|
||||||
|
let div_2 = x / i;
|
||||||
|
result.push(div_1);
|
||||||
|
|
||||||
|
if div_2 != div_1 {
|
||||||
|
result.push(div_2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.sort_unstable();
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(6, vec![1, 2, 3])]
|
||||||
|
#[case(28, vec![1, 2, 4, 7, 14])]
|
||||||
|
#[case(12_496, vec![1, 2, 4, 8, 11, 16, 22, 44, 71, 88, 142, 176, 284, 568, 781, 1136, 1562, 3124, 6248])]
|
||||||
|
fn proper_divisor(#[case] input: usize, #[case] expected: Vec<usize>) {
|
||||||
|
use crate::get_proper_divisors;
|
||||||
|
|
||||||
|
assert_eq!(get_proper_divisors(input), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(220, vec![vec![220, 284]])]
|
||||||
|
#[case(12_496, vec![vec![12_496, 14_288, 15_472, 14_536, 14_264]])]
|
||||||
|
fn chain(#[case] input: usize, #[case] expected: Vec<Vec<usize>>) {
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use crate::try_build_chain_from_number;
|
||||||
|
|
||||||
|
let max = expected.iter().flatten().max().unwrap().to_owned();
|
||||||
|
let mut part_of_any_chain = HashSet::new();
|
||||||
|
|
||||||
|
let mut chains = vec![];
|
||||||
|
try_build_chain_from_number(max, input, &mut chains, &mut part_of_any_chain);
|
||||||
|
|
||||||
|
assert_eq!(chains, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user