At first glance this looks like a simple directed graph exercise, which I Feel has been done at least once a year in every year I've done it. But at the very least, it seems pretty simple for part 1.
Either way, simple DFS should handle this.
var queue = new Queue<List<string>>();
queue.Enqueue(new List<string>() { "you" });
while (queue.TryDequeue(out var path))
{
foreach (var machine in connections[path.Last()])
{
if (machine == "out")
{
count++;
continue;
}
if (!path.Contains(machine))
{
var nextPath = new List<string>(path) { machine };
queue.Enqueue(nextPath);
}
}
}
Part 2 was just part 1, but bigger. Way way bigger. But honestly, just adding memoization to the DFS was enough to just make it stupidly fast.
private Dictionary<(string, string), long> memo = new();
private long CountPaths(string node, string end)
{
if (memo.TryGetValue((node, end), out var memoCount)) return memoCount;
long count = 0;
foreach (var machine in connections[node])
{
if (machine == end) count++;
else count += CountPaths(machine, end);
}
memo.Add((node, end), count);
return count;
}
It's great because it's reusable for Part 1, but also a second little trick for part 2 is just thinking of it as a few different smaller paths rather than one big path, and doing some simple math to get the full count.
(svr -> fft) * (fft -> dac) * (dac -> out)
+
(svr -> dac) * (dac -> fft) * (fft -> out)