day5, part2
This commit is contained in:
parent
aaae2a326c
commit
35ba924c1b
4 changed files with 194 additions and 1 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -24,6 +24,13 @@ dependencies = [
|
|||
name = "day04"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "day05"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["day01", "day02", "day03", "day04"]
|
||||
members = ["day01", "day02", "day03", "day04", "day05"]
|
||||
|
||||
[workspace.dependencies]
|
||||
winnow = "0.6"
|
||||
|
|
7
day05/Cargo.toml
Normal file
7
day05/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "day05"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
winnow.workspace = true
|
179
day05/src/main.rs
Normal file
179
day05/src/main.rs
Normal file
|
@ -0,0 +1,179 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use winnow::{
|
||||
PResult, Parser,
|
||||
ascii::{dec_uint, newline},
|
||||
combinator::{separated, separated_pair},
|
||||
error::ContextError,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let input = std::fs::read_to_string("input").unwrap();
|
||||
println!("{}", pt1(&input));
|
||||
println!("{}", pt2(&input));
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct Rule(u32, u32);
|
||||
|
||||
type Rules = Vec<Rule>;
|
||||
type Updates = Vec<Vec<u32>>;
|
||||
type Graph = HashMap<u32, HashSet<u32>>;
|
||||
|
||||
fn pt1(input: &str) -> u32 {
|
||||
let mut input = input;
|
||||
let (rules, updates) = parse(&mut input).unwrap();
|
||||
let mut total = 0;
|
||||
for update in updates {
|
||||
if check(&rules, &update) {
|
||||
let mid = update.len() / 2;
|
||||
total += update[mid];
|
||||
}
|
||||
}
|
||||
total
|
||||
}
|
||||
|
||||
fn check(rules: &Rules, update: &[u32]) -> bool {
|
||||
let mut pages = HashMap::new();
|
||||
for (i, p) in update.iter().enumerate() {
|
||||
pages.insert(p, i);
|
||||
}
|
||||
for rule in rules {
|
||||
let Rule(before, after) = rule;
|
||||
if let Some(u) = pages.get(before) {
|
||||
if let Some(v) = pages.get(after) {
|
||||
if v <= u {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn pt2(input: &str) -> u32 {
|
||||
let mut input = input;
|
||||
let mut total = 0;
|
||||
|
||||
let (rules, updates) = parse(&mut input).unwrap();
|
||||
|
||||
let mut neighbors = Graph::new();
|
||||
for rule in &rules {
|
||||
let Rule(u, v) = rule;
|
||||
neighbors.entry(*u).or_default().insert(*v);
|
||||
}
|
||||
|
||||
for update in updates {
|
||||
if !check(&rules, &update) {
|
||||
let sorted = tsort(&neighbors, &update);
|
||||
let mid = sorted.len() / 2;
|
||||
total += sorted[mid];
|
||||
}
|
||||
}
|
||||
|
||||
total
|
||||
}
|
||||
|
||||
fn tsort(graph: &Graph, nodes: &[u32]) -> Vec<u32> {
|
||||
let mut sorted = Vec::with_capacity(nodes.len());
|
||||
let mut processed = HashSet::with_capacity(nodes.len());
|
||||
let mut q = Vec::new();
|
||||
let nodes: HashSet<u32> = nodes.iter().copied().collect();
|
||||
|
||||
for node in nodes.iter() {
|
||||
q.push(*node);
|
||||
while let Some(current) = q.pop() {
|
||||
if !processed.contains(¤t) {
|
||||
q.push(current);
|
||||
}
|
||||
|
||||
let mut do_top = true;
|
||||
if let Some(nexts) = graph.get(¤t) {
|
||||
for n in nexts.iter().filter(|v| nodes.contains(v) && **v != current) {
|
||||
if !processed.contains(n) {
|
||||
q.push(*n);
|
||||
do_top = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if do_top {
|
||||
let _ = q.pop();
|
||||
if processed.insert(current) {
|
||||
sorted.push(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sorted
|
||||
}
|
||||
|
||||
fn p_rule(input: &mut &str) -> PResult<Rule> {
|
||||
let (a, b) = separated_pair(dec_uint, '|', dec_uint).parse_next(input)?;
|
||||
Ok(Rule(a, b))
|
||||
}
|
||||
|
||||
fn p_update(input: &mut &str) -> PResult<Vec<u32>> {
|
||||
separated(1.., dec_uint::<&str, u32, ContextError>, ',').parse_next(input)
|
||||
}
|
||||
|
||||
fn p_input(input: &mut &str) -> PResult<(Vec<Rule>, Updates)> {
|
||||
separated_pair(
|
||||
separated(1.., p_rule, newline),
|
||||
(newline, newline),
|
||||
separated(1.., p_update, newline),
|
||||
)
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parse(input: &mut &str) -> PResult<(Rules, Updates)> {
|
||||
let (rules, updates) = p_input(input)?;
|
||||
|
||||
Ok((rules, updates))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
static INPUT: &str = "47|53
|
||||
97|13
|
||||
97|61
|
||||
97|47
|
||||
75|29
|
||||
61|13
|
||||
75|53
|
||||
29|13
|
||||
97|29
|
||||
53|29
|
||||
61|53
|
||||
97|53
|
||||
61|29
|
||||
47|13
|
||||
75|47
|
||||
97|75
|
||||
47|61
|
||||
75|61
|
||||
47|29
|
||||
75|13
|
||||
53|13
|
||||
|
||||
75,47,61,53,29
|
||||
97,61,53,29,13
|
||||
75,29,13
|
||||
75,97,47,61,53
|
||||
61,13,29
|
||||
97,13,75,29,47";
|
||||
|
||||
#[test]
|
||||
fn p1() {
|
||||
let v = pt1(INPUT);
|
||||
assert_eq!(v, 143)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn p2() {
|
||||
assert_eq!(123, pt2(INPUT));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue