aboutsummaryrefslogtreecommitdiff
path: root/2018/src/day07.cpp
diff options
context:
space:
mode:
Diffstat (limited to '2018/src/day07.cpp')
-rw-r--r--2018/src/day07.cpp194
1 files changed, 194 insertions, 0 deletions
diff --git a/2018/src/day07.cpp b/2018/src/day07.cpp
new file mode 100644
index 0000000..e6147d6
--- /dev/null
+++ b/2018/src/day07.cpp
@@ -0,0 +1,194 @@
1#include <filesystem>
2#include <fstream>
3#include <iostream>
4#include <map>
5#include <set>
6#include <sstream>
7#include <string>
8#include <vector>
9
10using namespace std;
11
12namespace {
13
14vector<string>
15split(const string& line)
16{
17 stringstream strm{ line };
18 vector<string> words;
19
20 for ( string word; getline(strm, word, ' '); ) {
21 words.emplace_back(word);
22 }
23
24 return words;
25}
26
27map<string, set<string>>
28read_file(const filesystem::path& filename)
29{
30 ifstream file{ filename };
31 map<string, set<string>> graph;
32
33 for ( string line; getline(file, line); ) {
34 auto words = split(line);
35 graph[words.at(1)].emplace(words.at(7));
36 }
37
38 return graph;
39}
40
41vector<string>
42topologicalSort(const map<string, set<string>>& graph)
43{
44 map<string, int> indegree;
45
46 // Eingangsgrade initialisieren
47 for ( const auto& [node, neighbors]: graph ) {
48 if ( !indegree.contains(node) ) {
49 indegree[node] = 0;
50 }
51 for ( const auto& neighbor: neighbors ) {
52 indegree[neighbor]++;
53 }
54 }
55
56 // Queue mit Knoten, deren Eingangsgrad 0 ist
57 priority_queue<string, vector<string>, greater<>> queue;
58 for ( const auto& [node, deg]: indegree ) {
59 if ( deg == 0 ) {
60 queue.push(node);
61 }
62 }
63
64 vector<string> sorted;
65
66 // Kahn's Algorithmus
67 while ( !queue.empty() ) {
68 string node = queue.top();
69 queue.pop();
70
71 sorted.push_back(node);
72
73 if ( !graph.contains(node) ) {
74 continue;
75 }
76
77 for ( const auto& neighbor: graph.at(node) ) {
78 indegree[neighbor]--;
79 if ( indegree[neighbor] == 0 ) {
80 queue.push(neighbor);
81 }
82 }
83 }
84
85 // Prüfen auf Zyklus
86 if ( sorted.size() != indegree.size() ) {
87 throw runtime_error("Zyklus im Graph gefunden! Keine topologische Sortierung möglich.");
88 }
89
90 return sorted;
91}
92
93void
94part1(const map<string, set<string>>& graph)
95{
96 auto sorted = topologicalSort(graph);
97
98 cout << "Part 1: ";
99 ranges::copy(sorted, ostream_iterator<string>(cout));
100 cout << '\n';
101}
102
103void
104part2(const map<string, set<string>>& graph, const int workers, const int base)
105{
106 map<string, int> indegree;
107
108 // Eingangsgrade initialisieren
109 for ( const auto& [node, neighbors]: graph ) {
110 if ( !indegree.contains(node) ) {
111 indegree[node] = 0;
112 }
113 for ( const auto& neighbor: neighbors ) {
114 indegree[neighbor]++;
115 }
116 }
117
118 set<string> available;
119 for ( const auto& [node, deg]: indegree ) {
120 if ( deg == 0 ) {
121 available.insert(node);
122 }
123 }
124
125 set<pair<int, string>> finishing;
126
127 int active_workers = 0;
128 int time = 0;
129
130 while ( !indegree.empty() ) {
131 while ( !finishing.empty() && finishing.begin()->first == time ) {
132 auto [finish_time, node] = *finishing.begin();
133 finishing.erase(finishing.begin());
134
135 active_workers--;
136
137 indegree.erase(node);
138
139 if ( !graph.contains(node) ) {
140 continue;
141 }
142
143 for ( const auto& neighbor: graph.at(node) ) {
144 indegree[neighbor]--;
145 if ( indegree[neighbor] == 0 ) {
146 available.insert(neighbor);
147 }
148 }
149 }
150
151 while ( active_workers < workers && !available.empty() ) {
152 auto node = *available.begin();
153 available.erase(available.begin());
154
155 int duration = base + (node.at(0) - 'A' + 1);
156 int finish_time = time + duration;
157
158 finishing.emplace(finish_time, node);
159 active_workers++;
160 }
161
162 if ( finishing.empty() ) {
163 if ( available.empty() ) {
164 break;
165 }
166 else {
167 time++;
168 }
169 }
170 else {
171 time = finishing.begin()->first;
172 }
173 }
174
175 cout << "Part 2: " << time << '\n';
176}
177
178} // namespace
179
180int
181main()
182{
183 auto graph = read_file("data/day07.txt");
184 try {
185 part1(graph);
186
187 static const int WORKERS = 5;
188 static const int BASE = 60;
189 part2(graph, WORKERS, BASE);
190 }
191 catch ( exception& e ) {
192 cerr << "Fehler: " << e.what() << '\n';
193 }
194}