Skip to content

Commit e061b19

Browse files
committed
feat: 2022 Day 16 Part 2
1 parent 684cc4b commit e061b19

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

2022/day/16/part/2/solve.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import solve from "./solve.ts";
2+
3+
import { assertEquals } from "@std/assert";
4+
5+
Deno.test("example", () => {
6+
const input = `\
7+
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
8+
Valve BB has flow rate=13; tunnels lead to valves CC, AA
9+
Valve CC has flow rate=2; tunnels lead to valves DD, BB
10+
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
11+
Valve EE has flow rate=3; tunnels lead to valves FF, DD
12+
Valve FF has flow rate=0; tunnels lead to valves EE, GG
13+
Valve GG has flow rate=0; tunnels lead to valves FF, HH
14+
Valve HH has flow rate=22; tunnel leads to valve GG
15+
Valve II has flow rate=0; tunnels lead to valves AA, JJ
16+
Valve JJ has flow rate=21; tunnel leads to valve II`;
17+
18+
assertEquals(solve(input), 1707);
19+
});

2022/day/16/part/2/solve.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import subsets from "@lib/subsets.ts";
2+
3+
type ValueGraph = ReturnType<typeof parseFlowRateGraph>;
4+
type Distances = ReturnType<typeof computeDistances>;
5+
6+
const regExp =
7+
/^Valve (?<id>.+) has flow rate=(?<flowRateText>\d+); tunnels? leads? to valves? (?<destinationsText>.+?)$/gm;
8+
9+
function parseFlowRateGraph(text: string) {
10+
const flowRates = new Map<string, number>();
11+
const tunnels = new Map<string, string[]>();
12+
for (const { groups } of text.matchAll(regExp)) {
13+
const { id, flowRateText, destinationsText } = groups!;
14+
flowRates.set(id, +flowRateText);
15+
tunnels.set(id, destinationsText.split(", "));
16+
}
17+
const nodes = () => flowRates.keys();
18+
const value = (valve: string) => flowRates.get(valve);
19+
const connected = (valve: string) => tunnels.get(valve) ?? [];
20+
return { nodes, value, connected };
21+
}
22+
23+
function computeDistances(graph: ValueGraph) {
24+
const result = new Map<string, Map<string, number>>();
25+
{
26+
for (const u of graph.nodes()) {
27+
const u2 = new Map<string, number>().set(u, 0);
28+
result.set(u, u2);
29+
for (const v of graph.connected(u)) u2.set(v, 1), u2.set(v, 1);
30+
}
31+
for (const m of graph.nodes()) {
32+
for (const u of graph.nodes()) {
33+
const u2 = result.get(u)!;
34+
const u2m = u2.get(m);
35+
if (u2m === undefined) continue;
36+
for (const v of graph.nodes()) {
37+
const m2v = result.get(m)?.get(v);
38+
if (m2v === undefined) continue;
39+
const u2m2v = u2m + m2v;
40+
const u2v = u2.get(v);
41+
if (u2v !== undefined && u2v < u2m2v) continue;
42+
u2.set(v, u2m2v);
43+
}
44+
}
45+
}
46+
}
47+
return result;
48+
}
49+
50+
function findMaxPressure(
51+
graph: ValueGraph,
52+
distances: Distances,
53+
targets: Set<string>,
54+
) {
55+
let max = 0;
56+
const stack = [{
57+
valve: "AA",
58+
t: 26,
59+
opened: new Set<string>(),
60+
released: 0,
61+
}];
62+
while (stack.length) {
63+
const { valve, t, opened, released } = stack.pop()!;
64+
if (released > max) max = released;
65+
if (t === 0) continue;
66+
for (const destination of targets.difference(opened)) {
67+
const remaining = t - distances.get(valve)!.get(destination)! - 1;
68+
if (remaining < 0) continue;
69+
stack.push({
70+
valve: destination,
71+
t: remaining,
72+
opened: new Set(opened).add(destination),
73+
released: released + remaining * graph.value(destination)!,
74+
});
75+
}
76+
}
77+
return max;
78+
}
79+
80+
export default function solve(input: string) {
81+
const flowRateGraph = parseFlowRateGraph(input);
82+
const distances = computeDistances(flowRateGraph);
83+
const targets = flowRateGraph.nodes()
84+
.filter((valve) => flowRateGraph.value(valve))
85+
.reduce((set, value) => set.add(value), new Set<string>());
86+
const halfOfTargetsSize = targets.size / 2;
87+
const maxPressures = new Map<string, number>();
88+
for (const subtargets of subsets(targets)) {
89+
const maxPressure = findMaxPressure(flowRateGraph, distances, subtargets);
90+
maxPressures.set(`${[...subtargets]}`, maxPressure);
91+
}
92+
let max = 0;
93+
for (const yourTargets of subsets(targets)) {
94+
if (yourTargets.size > halfOfTargetsSize) continue;
95+
const theirTargets = targets.difference(yourTargets);
96+
const yourHash = `${[...yourTargets]}`, theirHash = `${[...theirTargets]}`;
97+
const combined = maxPressures.get(yourHash)! + maxPressures.get(theirHash)!;
98+
if (combined > max) max = combined;
99+
}
100+
return max;
101+
}

0 commit comments

Comments
 (0)