aboutsummaryrefslogtreecommitdiff
path: root/2024/src/day23.cpp
diff options
context:
space:
mode:
authorThomas Schmucker <ts@its1.de>2024-12-23 12:02:40 +0100
committerThomas Schmucker <ts@its1.de>2024-12-23 12:02:40 +0100
commite87bceffc3a19c0dd8acbcbc1b1195c60797ea5f (patch)
tree197ca43081ed6faaea6ddfcf8cdb097d20665a4a /2024/src/day23.cpp
parent12ba4504a7bbf3449552e37e8f28920e95b890c0 (diff)
downloadadvent-of-code-e87bceffc3a19c0dd8acbcbc1b1195c60797ea5f.tar.gz
advent-of-code-e87bceffc3a19c0dd8acbcbc1b1195c60797ea5f.tar.bz2
advent-of-code-e87bceffc3a19c0dd8acbcbc1b1195c60797ea5f.zip
aoc 2024, day 23, part 2
Diffstat (limited to '2024/src/day23.cpp')
-rw-r--r--2024/src/day23.cpp90
1 files changed, 90 insertions, 0 deletions
diff --git a/2024/src/day23.cpp b/2024/src/day23.cpp
index 45d6d28..36f40e6 100644
--- a/2024/src/day23.cpp
+++ b/2024/src/day23.cpp
@@ -20,6 +20,23 @@ split(const string& line, char sep = ' ')
20 return parts; 20 return parts;
21} 21}
22 22
23template<typename Container>
24string
25join(const Container& container, const string& delimiter)
26{
27 ostringstream oss;
28 auto it = container.begin();
29 if ( it != container.end() ) {
30 oss << *it;
31 ++it;
32 }
33 while ( it != container.end() ) {
34 oss << delimiter << *it;
35 ++it;
36 }
37 return oss.str();
38}
39
23map<string, set<string>> 40map<string, set<string>>
24read_file(string_view filename) 41read_file(string_view filename)
25{ 42{
@@ -57,9 +74,82 @@ part1(const map<string, set<string>>& nodes)
57 cout << connected.size() << endl; 74 cout << connected.size() << endl;
58} 75}
59 76
77void
78bronKerbosch(set<string> R, set<string> P, set<string> X, const map<string, set<string>>& graph, set<set<string>>& maxCliques)
79{
80 if ( P.empty() && X.empty() ) {
81 // Found a maximal clique
82 maxCliques.insert(R);
83 return;
84 }
85
86 // Choose a pivot (heuristic: choose a vertex with maximum connections in P union X)
87 string pivot;
88 set<string> unionPX;
89 set_union(P.begin(), P.end(), X.begin(), X.end(), inserter(unionPX, unionPX.begin()));
90
91 if ( !unionPX.empty() ) {
92 pivot = *unionPX.begin(); // Choose the first vertex as pivot (simple heuristic)
93 }
94
95 set<string> candidates;
96 set_difference(P.begin(), P.end(), graph.at(pivot).begin(), graph.at(pivot).end(), inserter(candidates, candidates.begin()));
97
98 for ( const string& candidate: candidates ) {
99 set<string> newR = R;
100 newR.insert(candidate);
101
102 set<string> newP;
103 set<string> newX;
104 for ( const string& neighbor: graph.at(candidate) ) {
105 if ( P.find(neighbor) != P.end() ) {
106 newP.insert(neighbor);
107 }
108 if ( X.find(neighbor) != X.end() ) {
109 newX.insert(neighbor);
110 }
111 }
112
113 bronKerbosch(newR, newP, newX, graph, maxCliques);
114
115 P.erase(candidate);
116 X.insert(candidate);
117 }
118}
119
120set<string>
121findLargestSet(const set<set<string>>& sets)
122{
123 set<string> largest;
124 for ( const auto& sub: sets ) {
125 if ( sub.size() > largest.size() ) {
126 largest = sub;
127 }
128 }
129 return largest;
130}
131
132void
133part2(const map<string, set<string>>& nodes)
134{
135 set<string> R; // Initially empty
136 set<string> P; // All vertices are potential candidates
137 set<string> X; // Initially empty
138
139 for ( const auto& [vertex, _]: nodes ) {
140 P.insert(vertex);
141 }
142
143 set<set<string>> max_cliques;
144 bronKerbosch(R, P, X, nodes, max_cliques);
145
146 cout << join(findLargestSet(max_cliques), ",") << endl;
147}
148
60int 149int
61main() 150main()
62{ 151{
63 auto data = read_file("data/day23.txt"); 152 auto data = read_file("data/day23.txt");
64 part1(data); 153 part1(data);
154 part2(data);
65} 155}