1use crate::util::bitset::*;
17use crate::util::iter::*;
18use crate::util::parse::*;
19
20struct Component {
21 left: usize,
22 right: usize,
23 weight: usize,
24 length: usize,
25}
26
27struct State {
28 possible: [usize; 64],
29 both: [usize; 64],
30 weight: [usize; 64],
31 length: [usize; 64],
32 bridge: [usize; 64],
33}
34
35pub fn parse(input: &str) -> [usize; 64] {
36 let mut components: Vec<_> = input
37 .iter_unsigned()
38 .chunk::<2>()
39 .map(|[left, right]| Component { left, right, weight: left + right, length: 1 })
40 .collect();
41
42 for n in 1..64 {
45 let mut indices = components.iter().enumerate().filter_map(|(index, component)| {
46 (component.left == n || component.right == n).then_some(index)
47 });
48
49 if let (Some(a), Some(b), None) = (indices.next(), indices.next(), indices.next()) {
50 let second = components.swap_remove(b);
51 let first = components.swap_remove(a);
52
53 let left = if first.left == n { first.right } else { first.left };
54 let right = if second.left == n { second.right } else { second.left };
55 let weight = first.weight + second.weight;
56 let length = first.length + second.length;
57
58 components.push(Component { left, right, weight, length });
59 }
60 }
61
62 components.sort_unstable_by_key(|c| (c.left ^ c.right, c.left));
65
66 let mut state = State {
67 possible: [0; 64],
68 both: [0; 64],
69 weight: [0; 64],
70 length: [0; 64],
71 bridge: [0; 64],
72 };
73
74 for (index, component) in components.iter().enumerate() {
75 let mask = 1 << index;
76 state.possible[component.left] |= mask;
77 state.possible[component.right] |= mask;
78
79 state.both[index] = component.left ^ component.right;
82 state.weight[index] = component.weight;
83 state.length[index] = component.length;
84 }
85
86 build(&mut state, 0, 0, 0, 0);
88 state.bridge
89}
90
91pub fn part1(input: &[usize]) -> usize {
93 *input.iter().max().unwrap()
94}
95
96pub fn part2(input: &[usize]) -> usize {
98 *input.iter().rfind(|&&n| n > 0).unwrap()
99}
100
101fn build(state: &mut State, current: usize, used: usize, strength: usize, length: usize) {
102 let remaining = state.possible[current] & !used;
104
105 for index in remaining.biterator() {
107 let next = current ^ state.both[index];
108 let new_used = used | (1 << index);
109 let new_strength = strength + state.weight[index];
110 let new_length = length + state.length[index];
111
112 if state.possible[next] & !new_used == 0 {
113 state.bridge[new_length] = state.bridge[new_length].max(new_strength);
115 } else {
116 build(state, next, new_used, new_strength, new_length);
117 if current == next {
121 break;
122 }
123 }
124 }
125}