-
Notifications
You must be signed in to change notification settings - Fork 0
/
2021_12.cs
108 lines (93 loc) · 2.81 KB
/
2021_12.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
namespace AOC.CSharp;
public static class AOC2021_12
{
public static long Solve1(string[] lines)
{
var graph = BuildGraph(lines);
return CountPaths(graph, false);
}
public static long Solve2(string[] lines)
{
var graph = BuildGraph(lines);
return CountPaths(graph, true);
}
private static long CountPaths(Dictionary<Node, List<Node>> graph, bool canVisitSmallTwice)
{
Node start = graph.Keys.Single(k => k.Type == NodeType.Start);
List<Node> visited = new();
int count = 0;
Recurse(graph, start, visited, ref count, !canVisitSmallTwice);
return count;
}
private static void Recurse(
Dictionary<Node, List<Node>> graph,
Node curr,
List<Node> visited,
ref int count,
bool smallVisitedTwice
)
{
visited.Add(curr);
var graphEntry = graph[curr];
foreach (Node next in graphEntry)
{
if (next.Type == NodeType.End)
{
count++;
}
else if (next.Type == NodeType.Large)
{
Recurse(graph, next, visited, ref count, smallVisitedTwice);
}
else if (next.Type == NodeType.Small && visited.Contains(next) && !smallVisitedTwice)
{
Recurse(graph, next, visited, ref count, true);
}
else if (next.Type == NodeType.Small && !visited.Contains(next))
{
Recurse(graph, next, visited, ref count, smallVisitedTwice);
}
}
visited.RemoveAt(visited.Count - 1);
}
private static Dictionary<Node, List<Node>> BuildGraph(string[] lines)
{
Dictionary<Node, List<Node>> graph = new();
void AddEdge(Node node1, Node node2)
{
if (!graph.TryGetValue(node1, out List<Node> nodes))
{
nodes = new List<Node>();
graph.Add(node1, nodes);
}
nodes.Add(node2);
}
foreach (string line in lines)
{
string[] splits = line.Split('-');
Node node1 = MakeNode(splits[0]);
Node node2 = MakeNode(splits[1]);
AddEdge(node1, node2);
AddEdge(node2, node1);
}
return graph;
}
private static Node MakeNode(string token)
{
if (token == "start")
return new Node(token, NodeType.Start);
if (token == "end")
return new Node(token, NodeType.End);
if (char.IsUpper(token[0]))
return new Node(token, NodeType.Large);
return new Node(token, NodeType.Small);
}
private record Node(string Name, NodeType Type);
private enum NodeType
{
Start,
End,
Large,
Small
}
}