summaryrefslogtreecommitdiff
path: root/2025/10/rust/src/main.rs
blob: b0cd6eda65fb2c53d6f2afb43c787ae877277384 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use good_lp::*;
use itertools::Itertools;
use std::io;

fn main() {
    let ms = io::stdin()
        .lines()
        .flatten()
        .map(|line| {
            let mut iter = line.split_whitespace();
            let p1 = iter
                .next()
                .unwrap()
                .chars()
                .filter_map(|ch| match ch {
                    '.' => Some(0),
                    '#' => Some(1),
                    _ => None,
                })
                .collect::<Vec<u32>>();

            let mut iter = iter.map(|s| {
                s.split(|ch: char| ch.is_ascii_punctuation())
                    .filter_map(|n| n.parse().ok())
                    .collect::<Vec<u32>>()
            });
            let p2 = iter.next_back().unwrap();
            let bs = iter.collect::<Vec<_>>();
            (p1, p2, bs)
        })
        .collect::<Vec<_>>();

    let silver: usize = ms.iter().map(|(want, _, bs)| solve_p1(&want, &bs)).sum();
    let gold: usize = ms.iter().map(|(_, want, bs)| solve_p2(&want, &bs)).sum();
    println!("silver: {silver}");
    println!("gold: {gold}");
}

fn solve_p1(want: &Vec<u32>, bs: &Vec<Vec<u32>>) -> usize {
    bs.into_iter()
        .powerset()
        .map(|sub| (sub.len(), sub.into_iter().flatten().counts()))
        .filter(|(_, counts)| {
            want.iter()
                .enumerate()
                .all(|(n, w)| counts.get(&(n as u32)).unwrap_or(&0) % 2 == *w as usize)
        })
        .next()
        .unwrap()
        .0
}

fn solve_p2(want: &Vec<u32>, bs: &Vec<Vec<u32>>) -> usize {
    variables! {vars: 0 <= xs[bs.len()] (integer);}
    let obj: Expression = xs.iter().sum();
    let mut model = vars.minimise(&obj).using(default_solver);
    for (n, w) in want.iter().enumerate() {
        let xsum: Expression = bs
            .iter()
            .enumerate()
            .filter(|&(_, b)| b.contains(&(n as u32)))
            .map(|(x, _)| xs[x])
            .sum();
        model = model.with(constraint!(xsum == *w));
    }

    model.solve().unwrap().eval(&obj).round() as usize
}