Skip to content

Commit 12c6bbe

Browse files
committed
day25: implement solution in Rust
At first glance, the puzzle seems to be asking for the min cut that divides the two sub-graphs, implying the use of an algorithm like Stoer-Wagner or Karger, but since we already know that the min cut is three edges, we can instead find the three shortest paths between two random points, remove them all, and if there isn't a fourth, the sub-graphs are divided. From there, a simple flood fill from a single vertex is enough to calculate the answer.
1 parent 7583ad7 commit 12c6bbe

File tree

4 files changed

+124
-0
lines changed

4 files changed

+124
-0
lines changed

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ members = [
4848
"day23pt2",
4949
"day24",
5050
"day24pt2",
51+
"day25",
5152
]
5253

5354
[profile.dev]

day25/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "day25"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]

day25/src/main.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use std::collections::{HashMap, VecDeque};
2+
3+
fn find_path(graph: &Vec<Vec<u16>>, start: u16, goal: u16) -> Option<Vec<u16>> {
4+
let mut came_from: Vec<Option<u16>> = vec![None; graph.len()];
5+
let mut queue: VecDeque<u16> = VecDeque::new();
6+
queue.push_back(start);
7+
while let Some(current) = queue.pop_front() {
8+
for adjacent in graph[current as usize].iter().copied() {
9+
if came_from[adjacent as usize].is_none() {
10+
came_from[adjacent as usize] = Some(current);
11+
if adjacent == goal {
12+
let mut path: Vec<u16> = vec![goal];
13+
let mut prev = came_from[goal as usize];
14+
while let Some(prev_inner) = prev {
15+
path.push(prev_inner);
16+
if prev_inner == start {
17+
break;
18+
}
19+
prev = came_from[prev_inner as usize];
20+
}
21+
return Some(path);
22+
}
23+
queue.push_back(adjacent);
24+
}
25+
}
26+
}
27+
return None;
28+
}
29+
30+
fn remove_path(graph: &mut Vec<Vec<u16>>, path: &[u16]) {
31+
for edge in path.windows(2) {
32+
let a = edge[0];
33+
let b = edge[1];
34+
graph[a as usize].retain(|&x| x != b);
35+
graph[b as usize].retain(|&x| x != a);
36+
}
37+
}
38+
39+
fn count_subgraph(graph: &Vec<Vec<u16>>, start: u16, avoid: u16) -> Option<usize> {
40+
let mut visited: Vec<bool> = vec![false; graph.len()];
41+
let mut queue: VecDeque<u16> = VecDeque::new();
42+
visited[start as usize] = true;
43+
queue.push_back(start);
44+
while let Some(current) = queue.pop_front() {
45+
for adjacent in graph[current as usize].iter().copied() {
46+
if !visited[adjacent as usize] {
47+
visited[adjacent as usize] = true;
48+
if adjacent == avoid {
49+
return None;
50+
}
51+
queue.push_back(adjacent);
52+
}
53+
}
54+
}
55+
return Some(visited.iter().filter(|&v| *v).count());
56+
}
57+
58+
fn main() {
59+
let mut labels: HashMap<String, u16> = HashMap::new();
60+
let mut graph: Vec<Vec<u16>> = Vec::new();
61+
62+
for line in std::io::stdin().lines().map(Result::unwrap) {
63+
let mut tokens = line.split_whitespace();
64+
65+
let label1 = tokens.next().expect("label1").trim_end_matches(':');
66+
let labels_len = labels.len();
67+
let vertex1 = *labels
68+
.entry(label1.to_string())
69+
.or_insert(labels_len.try_into().expect("new u16 vertex"));
70+
if vertex1 as usize >= graph.len() {
71+
graph.resize(vertex1 as usize + 1, Vec::new());
72+
}
73+
74+
for label2 in tokens {
75+
let labels_len = labels.len();
76+
let vertex2 = *labels
77+
.entry(label2.to_string())
78+
.or_insert(labels_len.try_into().expect("new u16 vertex"));
79+
if vertex2 as usize >= graph.len() {
80+
graph.resize(vertex2 as usize + 1, Vec::new());
81+
}
82+
graph[vertex1 as usize].push(vertex2);
83+
graph[vertex2 as usize].push(vertex1);
84+
}
85+
}
86+
87+
for a in 0..graph.len() - 1 {
88+
for b in a + 1..graph.len() {
89+
let a = u16::try_from(a).expect("u16 a");
90+
let b = u16::try_from(b).expect("u16 b");
91+
92+
let mut temp_graph = graph.clone();
93+
let path1 = find_path(&temp_graph, a, b).expect("path1");
94+
remove_path(&mut temp_graph, &path1[..]);
95+
let path2 = find_path(&temp_graph, a, b).expect("path2");
96+
remove_path(&mut temp_graph, &path2[..]);
97+
let path3 = find_path(&temp_graph, a, b).expect("path3");
98+
remove_path(&mut temp_graph, &path3[..]);
99+
100+
if let Some(size) = count_subgraph(&temp_graph, a, b) {
101+
println!(
102+
"{} * {} = {}",
103+
size,
104+
graph.len() - size,
105+
size * (graph.len() - size),
106+
);
107+
return;
108+
}
109+
}
110+
}
111+
}

0 commit comments

Comments
 (0)