mirror of
https://github.com/parnic/advent-of-code-2022.git
synced 2025-06-16 13:40:13 -05:00
Day 16 solution
I spent an inordinately long amount of time on part 2, only to discover a fundamental flaw in my logic. Apparently for my input set, switching to the other person every time the first person had less time remaining meant that some combinations never got tested. The solution in this commit exhausts every option for one person, then every option for the second person (or animal...) which works for my test input. I have a feeling it won't work for all, though.
This commit is contained in:
@ -69,6 +69,7 @@
|
||||
<EmbeddedResource Include="inputs\15a.txt" />
|
||||
<EmbeddedResource Include="inputs\16.txt" />
|
||||
<None Remove="inputs\17.txt" />
|
||||
<EmbeddedResource Include="inputs\16a.txt" />
|
||||
<EmbeddedResource Include="inputs\17.txt" />
|
||||
<None Remove="inputs\18.txt" />
|
||||
<EmbeddedResource Include="inputs\17a.txt" />
|
||||
|
@ -1 +1,60 @@
|
||||
A20D5080210CE4BB9BAFB001BD14A4574C014C004AE46A9B2E27297EECF0C013F00564776D7E3A825CAB8CD47B6C537DB99CD746674C1000D29BBC5AC80442966FB004C401F8771B61D8803D0B22E4682010EE7E59ACE5BC086003E3270AE4024E15C8010073B2FAD98E004333F9957BCB602E7024C01197AD452C01295CE2DC9934928B005DD258A6637F534CB3D89A944230043801A596B234B7E58509E88798029600BCF5B3BA114F5B3BA10C9E77BAF20FA4016FCDD13340118B929DD4FD54E60327C00BEB7002080AA850031400D002369400B10034400F30021400F20157D804AD400FE00034E000A6D001EB2004E5C00B9AE3AC3C300470029091ACADBFA048D656DFD126792187008635CD736B3231A51BA5EBDF42D4D299804F26B33C872E213C840022EC9C21FFB34EDE7C559C8964B43F8AD77570200FC66697AFEB6C757AC0179AB641E6AD9022006065CEA714A4D24C0179F8E795D3078026200FC118EB1B40010A8D11EA27100990200C45A83F12C401A8611D60A0803B1723542889537EFB24D6E0844004248B1980292D608D00423F49F9908049798B4452C0131006230C14868200FC668B50650043196A7F95569CF6B663341535DCFE919C464400A96DCE1C6B96D5EEFE60096006A400087C1E8610A4401887D1863AC99F9802DC00D34B5BCD72D6F36CB6E7D95EBC600013A88010A8271B6281803B12E124633006A2AC3A8AC600BCD07C9851008712DEAE83A802929DC51EE5EF5AE61BCD0648028596129C3B98129E5A9A329ADD62CCE0164DDF2F9343135CCE2137094A620E53FACF37299F0007392A0B2A7F0BA5F61B3349F3DFAEDE8C01797BD3F8BC48740140004322246A8A2200CC678651AA46F09AEB80191940029A9A9546E79764F7C9D608EA0174B63F815922999A84CE7F95C954D7FD9E0890047D2DC13B0042488259F4C0159922B0046565833828A00ACCD63D189D4983E800AFC955F211C700
|
||||
Valve NQ has flow rate=0; tunnels lead to valves SU, XD
|
||||
Valve AB has flow rate=0; tunnels lead to valves XD, TE
|
||||
Valve IA has flow rate=0; tunnels lead to valves CS, WF
|
||||
Valve WD has flow rate=0; tunnels lead to valves DW, II
|
||||
Valve XD has flow rate=10; tunnels lead to valves AB, NQ, VT, SC, MU
|
||||
Valve SL has flow rate=0; tunnels lead to valves RP, DS
|
||||
Valve FQ has flow rate=15; tunnels lead to valves EI, YC
|
||||
Valve KF has flow rate=0; tunnels lead to valves FL, QP
|
||||
Valve QP has flow rate=0; tunnels lead to valves KF, RP
|
||||
Valve DS has flow rate=0; tunnels lead to valves SL, AA
|
||||
Valve IK has flow rate=0; tunnels lead to valves XC, AA
|
||||
Valve HQ has flow rate=0; tunnels lead to valves VM, WV
|
||||
Valve WR has flow rate=0; tunnels lead to valves WV, HF
|
||||
Valve HH has flow rate=20; tunnels lead to valves PI, CF, CN, NF, AR
|
||||
Valve DW has flow rate=19; tunnels lead to valves KD, WD, HS
|
||||
Valve RP has flow rate=14; tunnels lead to valves SL, QP, BH, LI, WP
|
||||
Valve EC has flow rate=0; tunnels lead to valves NF, XC
|
||||
Valve AA has flow rate=0; tunnels lead to valves NH, ES, UC, IK, DS
|
||||
Valve VM has flow rate=18; tunnel leads to valve HQ
|
||||
Valve NF has flow rate=0; tunnels lead to valves HH, EC
|
||||
Valve PS has flow rate=0; tunnels lead to valves AR, SU
|
||||
Valve IL has flow rate=0; tunnels lead to valves XC, KZ
|
||||
Valve WP has flow rate=0; tunnels lead to valves CS, RP
|
||||
Valve WF has flow rate=0; tunnels lead to valves FL, IA
|
||||
Valve XW has flow rate=0; tunnels lead to valves OL, NL
|
||||
Valve EH has flow rate=0; tunnels lead to valves UK, YR
|
||||
Valve UC has flow rate=0; tunnels lead to valves AA, FL
|
||||
Valve CS has flow rate=3; tunnels lead to valves IA, CN, LD, RJ, WP
|
||||
Valve AR has flow rate=0; tunnels lead to valves PS, HH
|
||||
Valve CF has flow rate=0; tunnels lead to valves HH, FL
|
||||
Valve NH has flow rate=0; tunnels lead to valves AA, LD
|
||||
Valve RJ has flow rate=0; tunnels lead to valves DJ, CS
|
||||
Valve XC has flow rate=17; tunnels lead to valves IL, EC, YR, IK, DJ
|
||||
Valve TE has flow rate=24; tunnels lead to valves AB, YA
|
||||
Valve CN has flow rate=0; tunnels lead to valves HH, CS
|
||||
Valve KD has flow rate=0; tunnels lead to valves DW, UK
|
||||
Valve SC has flow rate=0; tunnels lead to valves EI, XD
|
||||
Valve MU has flow rate=0; tunnels lead to valves XD, YP
|
||||
Valve SU has flow rate=22; tunnels lead to valves PS, LI, II, NQ
|
||||
Valve FL has flow rate=8; tunnels lead to valves KF, WF, CF, UC, HS
|
||||
Valve OL has flow rate=4; tunnels lead to valves KZ, HF, XW
|
||||
Valve EI has flow rate=0; tunnels lead to valves FQ, SC
|
||||
Valve NL has flow rate=0; tunnels lead to valves XW, UK
|
||||
Valve YP has flow rate=21; tunnels lead to valves YA, MU, YC
|
||||
Valve BH has flow rate=0; tunnels lead to valves VT, RP
|
||||
Valve II has flow rate=0; tunnels lead to valves SU, WD
|
||||
Valve YA has flow rate=0; tunnels lead to valves TE, YP
|
||||
Valve HS has flow rate=0; tunnels lead to valves FL, DW
|
||||
Valve DJ has flow rate=0; tunnels lead to valves RJ, XC
|
||||
Valve KZ has flow rate=0; tunnels lead to valves OL, IL
|
||||
Valve YR has flow rate=0; tunnels lead to valves EH, XC
|
||||
Valve UK has flow rate=7; tunnels lead to valves KD, NL, EH
|
||||
Valve YC has flow rate=0; tunnels lead to valves FQ, YP
|
||||
Valve ES has flow rate=0; tunnels lead to valves PI, AA
|
||||
Valve LI has flow rate=0; tunnels lead to valves SU, RP
|
||||
Valve LD has flow rate=0; tunnels lead to valves NH, CS
|
||||
Valve VT has flow rate=0; tunnels lead to valves BH, XD
|
||||
Valve PI has flow rate=0; tunnels lead to valves ES, HH
|
||||
Valve WV has flow rate=11; tunnels lead to valves WR, HQ
|
||||
Valve HF has flow rate=0; tunnels lead to valves OL, WR
|
10
inputs/16a.txt
Normal file
10
inputs/16a.txt
Normal file
@ -0,0 +1,10 @@
|
||||
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
|
||||
Valve BB has flow rate=13; tunnels lead to valves CC, AA
|
||||
Valve CC has flow rate=2; tunnels lead to valves DD, BB
|
||||
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
|
||||
Valve EE has flow rate=3; tunnels lead to valves FF, DD
|
||||
Valve FF has flow rate=0; tunnels lead to valves EE, GG
|
||||
Valve GG has flow rate=0; tunnels lead to valves FF, HH
|
||||
Valve HH has flow rate=22; tunnel leads to valve GG
|
||||
Valve II has flow rate=0; tunnels lead to valves AA, JJ
|
||||
Valve JJ has flow rate=21; tunnel leads to valve II
|
197
src/16.cs
Normal file
197
src/16.cs
Normal file
@ -0,0 +1,197 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace aoc2022;
|
||||
|
||||
internal partial class Day16 : Day
|
||||
{
|
||||
private class valve : IEquatable<valve>
|
||||
{
|
||||
public string name = string.Empty;
|
||||
public int flowRate = 0;
|
||||
public List<string> connectedValveNames = new();
|
||||
public readonly List<valve> connectedValves = new();
|
||||
public bool isOpen = false;
|
||||
|
||||
public valve()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public bool Equals(valve? other) => name == other?.name;
|
||||
public override bool Equals(object? obj) => obj is valve other && Equals(other);
|
||||
public override int GetHashCode() => name.GetHashCode();
|
||||
public static bool operator ==(valve left, valve right) => left.Equals(right);
|
||||
public static bool operator !=(valve left, valve right) => !left.Equals(right);
|
||||
|
||||
public override string ToString() => $"[{name}] {flowRate} -> {string.Join(", ", connectedValveNames)}";
|
||||
}
|
||||
private readonly List<valve> valves = new();
|
||||
|
||||
[GeneratedRegex("Valve ([^ ]+) has flow rate=(\\d+); tunnels? leads? to valves? (.+)", RegexOptions.Compiled)]
|
||||
private static partial Regex LineRegex();
|
||||
|
||||
internal override void Parse()
|
||||
{
|
||||
var r = LineRegex();
|
||||
foreach (var line in Util.Parsing.ReadAllLines("16"))
|
||||
{
|
||||
var match = r.Match(line);
|
||||
valves.Add(new valve
|
||||
{
|
||||
name = match.Groups[1].Value,
|
||||
flowRate = int.Parse(match.Groups[2].Value),
|
||||
connectedValveNames = new List<string>(match.Groups[3].Value.Split(", ")),
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var valve in valves)
|
||||
{
|
||||
foreach (var connected in valve.connectedValveNames)
|
||||
{
|
||||
valve.connectedValves.Add(valves.First(v => v.name == connected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<(valve, valve), int> distanceMap = new();
|
||||
private int shortestPath(valve from, valve to)
|
||||
{
|
||||
if (from == to)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (distanceMap.ContainsKey((from, to)))
|
||||
{
|
||||
return distanceMap[(from, to)];
|
||||
}
|
||||
|
||||
Dictionary<valve, int> d = new() {{from, 0}};
|
||||
HashSet<valve> unvisited = new(valves.Where(v => v != from));
|
||||
valve current = from;
|
||||
while (true)
|
||||
{
|
||||
int dist = d[current!];
|
||||
foreach (var v in unvisited.Where(v => current!.connectedValves.Contains(v)))
|
||||
{
|
||||
if (!d.ContainsKey(v) || d[v] > dist + 1)
|
||||
{
|
||||
d[v] = dist + 1;
|
||||
}
|
||||
}
|
||||
|
||||
unvisited.Remove(current!);
|
||||
if (current! == to)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
current = unvisited.MinBy(v => !d.ContainsKey(v) ? int.MaxValue : d[v])!;
|
||||
}
|
||||
|
||||
distanceMap[(from, to)] = d[to];
|
||||
return d[to];
|
||||
}
|
||||
|
||||
private readonly Dictionary<(int, valve, ICollection<valve>), int> routes = new();
|
||||
|
||||
private int findBestRoute(int timeLeft, valve startValve, ICollection<valve> openValves)
|
||||
{
|
||||
// if (routes.TryGetValue((timeLeft, startValve, openValves), out int retval))
|
||||
// {
|
||||
// return retval;
|
||||
// }
|
||||
|
||||
if (timeLeft <= 2 || valves.All(v => v.isOpen || v.flowRate == 0))
|
||||
{
|
||||
// routes.Add((timeLeft, startValve, openValves), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
startValve.isOpen = true;
|
||||
|
||||
var pq = new PriorityQueue<valve, int>();
|
||||
foreach (var v in valves.Where(v => v is {isOpen: false, flowRate: > 0}))
|
||||
{
|
||||
var dist = shortestPath(startValve, v);
|
||||
if (dist + 1 >= timeLeft)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var minutesValveContributes = (timeLeft - dist - 1);
|
||||
var priority = v.flowRate * minutesValveContributes;
|
||||
// var nextOpen = new HashSet<valve>(openValves) {v};
|
||||
var totalFlow = findBestRoute(minutesValveContributes, v, openValves);
|
||||
|
||||
pq.Enqueue(v, -(priority + totalFlow));
|
||||
}
|
||||
|
||||
startValve.isOpen = false;
|
||||
pq.TryDequeue(out valve _, out int p);
|
||||
// routes.Add((timeLeft, startValve, openValves), -p);
|
||||
return -p;
|
||||
}
|
||||
|
||||
private int findBestRouteDuo(int timeLeftA, valve startValveA, int timeLeftB, valve startValveB, ICollection<valve> openValves)
|
||||
{
|
||||
// if (timeLeftB > timeLeftA)
|
||||
if (timeLeftA <= 2)
|
||||
{
|
||||
(timeLeftA, startValveA, timeLeftB, startValveB) = (timeLeftB, startValveB, timeLeftA, startValveA);
|
||||
}
|
||||
|
||||
// if (routes.TryGetValue((timeLeftA, startValveA, openValves), out int retval))
|
||||
// {
|
||||
// return retval;
|
||||
// }
|
||||
|
||||
if (timeLeftA <= 2 || valves.All(v => v.isOpen || v.flowRate == 0))
|
||||
{
|
||||
// routes.Add((timeLeftA, startValveA, openValves), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
var pq = new PriorityQueue<valve, int>();
|
||||
foreach (var v in valves.Where(v => v is {isOpen: false, flowRate: > 0}))
|
||||
{
|
||||
var dist = shortestPath(startValveA, v);
|
||||
if (dist + 1 >= timeLeftA)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var minutesValveContributes = (timeLeftA - dist - 1);
|
||||
var priority = v.flowRate * minutesValveContributes;
|
||||
// var nextOpen = new HashSet<valve>(openValves) {v};
|
||||
v.isOpen = true;
|
||||
int totalFlow = findBestRouteDuo(minutesValveContributes, v, timeLeftB, startValveB, openValves);
|
||||
v.isOpen = false;
|
||||
pq.Enqueue(v, -(priority + totalFlow));
|
||||
}
|
||||
|
||||
pq.TryDequeue(out valve _, out int p);
|
||||
// routes.Add((timeLeftA, startValveA, openValves), -p);
|
||||
return -p;
|
||||
}
|
||||
|
||||
internal override string Part1()
|
||||
{
|
||||
var openValves = new HashSet<valve>(valves.Where(v => v.flowRate == 0));
|
||||
|
||||
int timeLeft = 30;
|
||||
valve currentValve = valves.First(v => v.name == "AA");
|
||||
var totalFlow = findBestRoute(timeLeft, currentValve, openValves);
|
||||
return $"<+white>{totalFlow}";
|
||||
}
|
||||
|
||||
internal override string Part2()
|
||||
{
|
||||
var openValves = new HashSet<valve>(valves.Where(v => v.flowRate == 0));
|
||||
|
||||
int timeLeft = 26;
|
||||
valve currentValve = valves.First(v => v.name == "AA");
|
||||
var totalFlow = findBestRouteDuo(timeLeft, currentValve, timeLeft, currentValve, openValves);
|
||||
return $"<+white>{totalFlow}";
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user