diff options
Diffstat (limited to 'src/day25.cpp')
| -rw-r--r-- | src/day25.cpp | 159 |
1 files changed, 35 insertions, 124 deletions
diff --git a/src/day25.cpp b/src/day25.cpp index b566725..aaad9e9 100644 --- a/src/day25.cpp +++ b/src/day25.cpp | |||
| @@ -1,11 +1,10 @@ | |||
| 1 | #include <algorithm> | 1 | #include <algorithm> |
| 2 | #include <cstdlib> | 2 | #include <array> |
| 3 | #include <fstream> | 3 | #include <fstream> |
| 4 | #include <iostream> | 4 | #include <iostream> |
| 5 | #include <iterator> | ||
| 6 | #include <list> | ||
| 7 | #include <map> | 5 | #include <map> |
| 8 | #include <queue> | 6 | #include <queue> |
| 7 | #include <random> | ||
| 9 | #include <set> | 8 | #include <set> |
| 10 | #include <sstream> | 9 | #include <sstream> |
| 11 | #include <string> | 10 | #include <string> |
| @@ -47,48 +46,7 @@ read_file(string_view filename) | |||
| 47 | } | 46 | } |
| 48 | 47 | ||
| 49 | bool | 48 | bool |
| 50 | bfs(const graph_type& graph, const string& source, const string& dest, map<string, string>& parents) // NOLINT | 49 | bfs(graph_type graph, const string& source, const string& dest, function<void(const string&, const string&)> visit) // NOLINT |
| 51 | { | ||
| 52 | set<string> visited; | ||
| 53 | |||
| 54 | parents.clear(); | ||
| 55 | |||
| 56 | queue<string> queue; | ||
| 57 | queue.emplace(source); | ||
| 58 | |||
| 59 | while ( !queue.empty() ) { | ||
| 60 | auto candidate = queue.front(); | ||
| 61 | queue.pop(); | ||
| 62 | |||
| 63 | if ( candidate == dest ) { | ||
| 64 | return true; | ||
| 65 | } | ||
| 66 | |||
| 67 | for ( const auto& neighbour: graph.at(candidate) ) { | ||
| 68 | if ( !visited.contains(neighbour) ) { | ||
| 69 | queue.emplace(neighbour); | ||
| 70 | parents[neighbour] = candidate; | ||
| 71 | visited.emplace(neighbour); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | return false; | ||
| 77 | } | ||
| 78 | |||
| 79 | void | ||
| 80 | dfs(const graph_type& graph, const string& source, set<string>& visited) // NOLINT | ||
| 81 | { | ||
| 82 | visited.emplace(source); | ||
| 83 | for ( const auto& node: graph.at(source) ) { | ||
| 84 | if ( !visited.contains(node) ) { | ||
| 85 | dfs(graph, node, visited); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | bool | ||
| 91 | bfs1(graph_type graph, const string& source, const string& dest, function<void(const string&, const string&)> visit) // NOLINT | ||
| 92 | { | 50 | { |
| 93 | set<string> visited; | 51 | set<string> visited; |
| 94 | 52 | ||
| @@ -115,115 +73,68 @@ bfs1(graph_type graph, const string& source, const string& dest, function<void(c | |||
| 115 | return false; | 73 | return false; |
| 116 | } | 74 | } |
| 117 | 75 | ||
| 118 | void | 76 | auto |
| 119 | print_graph_stats(const graph_type& graph) | 77 | random_node(const graph_type& graph) |
| 120 | { | 78 | { |
| 121 | size_t nodes = 0; | 79 | static random_device dev; |
| 122 | size_t edges = 0; | 80 | static mt19937 generator(dev()); |
| 123 | for ( const auto& link: graph ) { | 81 | |
| 124 | nodes++; | 82 | uniform_int_distribution<graph_type::size_type> distribute(0, graph.size()); |
| 125 | edges += link.second.size(); | 83 | |
| 126 | } | 84 | auto iter = graph.begin(); |
| 127 | cout << nodes << ", " << edges / 2 << endl; | 85 | advance(iter, distribute(generator)); |
| 86 | return iter->first; | ||
| 128 | } | 87 | } |
| 129 | 88 | ||
| 130 | void | 89 | void |
| 131 | part1(graph_type graph) | 90 | part1(graph_type graph) |
| 132 | { | 91 | { |
| 133 | srand(unsigned(time(nullptr))); | 92 | map<tuple<string, string>, int> frequencies; |
| 134 | |||
| 135 | vector<string> nodes(graph.size()); | ||
| 136 | for ( const auto& foo: graph ) { | ||
| 137 | nodes.emplace_back(foo.first); | ||
| 138 | } | ||
| 139 | |||
| 140 | map<tuple<string, string>, int> counter; | ||
| 141 | for ( size_t idx = 0; idx != 2; ++idx ) { | 93 | for ( size_t idx = 0; idx != 2; ++idx ) { |
| 142 | for ( const auto& second: graph ) { | 94 | for ( const auto& second: graph ) { |
| 143 | bfs1(graph, nodes[size_t(rand()) % nodes.size()], second.first, [&](const string& candidate, const string& neighbour) { | 95 | bfs(graph, random_node(graph), second.first, [&](const string& candidate, const string& neighbour) { |
| 144 | if ( candidate < neighbour ) { | 96 | if ( candidate < neighbour ) { |
| 145 | counter[make_tuple(candidate, neighbour)]++; | 97 | frequencies[make_tuple(candidate, neighbour)]++; |
| 146 | } | 98 | } |
| 147 | else { | 99 | else { |
| 148 | counter[make_tuple(neighbour, candidate)]++; | 100 | frequencies[make_tuple(neighbour, candidate)]++; |
| 149 | } | 101 | } |
| 150 | }); | 102 | }); |
| 151 | } | 103 | } |
| 152 | } | 104 | } |
| 153 | 105 | ||
| 154 | vector<tuple<tuple<string, string>, int>> all_links{ counter.begin(), counter.end() }; | 106 | vector<tuple<tuple<string, string>, int>> sorted_frequencies{ frequencies.begin(), frequencies.end() }; |
| 155 | 107 | ||
| 156 | sort(all_links.begin(), all_links.end(), [](const auto& lhs, const auto& rhs) { | 108 | sort(sorted_frequencies.begin(), sorted_frequencies.end(), [](const auto& lhs, const auto& rhs) { |
| 157 | return get<1>(lhs) > get<1>(rhs); | 109 | return get<1>(lhs) > get<1>(rhs); |
| 158 | }); | 110 | }); |
| 159 | 111 | ||
| 160 | for ( size_t i = 0; i != 3; ++i ) { | 112 | sorted_frequencies.erase(sorted_frequencies.begin() + 3, sorted_frequencies.end()); |
| 161 | const auto [links, num] = all_links[i]; | ||
| 162 | const auto [lhs, rhs] = links; | ||
| 163 | 113 | ||
| 164 | graph[lhs].erase(rhs); | 114 | for ( const auto& link: sorted_frequencies ) { |
| 165 | graph[rhs].erase(lhs); | 115 | const auto [left, right] = get<0>(link); |
| 116 | |||
| 117 | graph[left].erase(right); | ||
| 118 | graph[right].erase(left); | ||
| 166 | } | 119 | } |
| 167 | 120 | ||
| 168 | set<string> reachable; | 121 | auto reachable = [&graph](const string& start_node) { |
| 169 | const auto start_from_a = get<0>(get<0>(all_links[0])); | 122 | set<string> nodes; |
| 170 | bfs1(graph, start_from_a, "--not there--", [&](const string& candidate, const string& neighbour) { | 123 | bfs(graph, start_node, "", [&nodes](const string& candidate, const string& neighbour) { |
| 171 | reachable.insert(candidate); | 124 | nodes.insert(candidate); |
| 172 | reachable.insert(neighbour); | 125 | nodes.insert(neighbour); |
| 173 | }); | 126 | }); |
| 127 | return nodes.size(); | ||
| 128 | }; | ||
| 174 | 129 | ||
| 175 | set<string> reachable2; | 130 | const auto [left, right] = get<0>(sorted_frequencies[0]); |
| 176 | const auto start_from_b = get<1>(get<0>(all_links[0])); | ||
| 177 | bfs1(graph, start_from_b, "--not there--", [&](const string& candidate, const string& neighbour) { | ||
| 178 | reachable2.insert(candidate); | ||
| 179 | reachable2.insert(neighbour); | ||
| 180 | }); | ||
| 181 | 131 | ||
| 182 | cout << reachable.size() * reachable2.size() << endl; | 132 | cout << reachable(left) * reachable(right) << endl; |
| 183 | } | ||
| 184 | |||
| 185 | void | ||
| 186 | print_graph(const graph_type& graph) | ||
| 187 | { | ||
| 188 | for ( const auto& node: graph ) { | ||
| 189 | cout << node.first << ": "; | ||
| 190 | copy(node.second.begin(), node.second.end(), ostream_iterator<string>(cout, ", ")); | ||
| 191 | cout << endl; | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | graph_type | ||
| 196 | get_rgraph(const graph_type& graph) | ||
| 197 | { | ||
| 198 | graph_type rgraph; | ||
| 199 | for ( const auto& node: graph ) { | ||
| 200 | for ( const auto& link: node.second ) { | ||
| 201 | rgraph[link].insert(node.first); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | return rgraph; | ||
| 205 | } | 133 | } |
| 206 | 134 | ||
| 207 | int | 135 | int |
| 208 | main() | 136 | main() |
| 209 | { | 137 | { |
| 210 | auto graph = read_file("data/day25.txt"); | 138 | auto graph = read_file("data/day25.txt"); |
| 211 | |||
| 212 | // print_graph(graph); | ||
| 213 | |||
| 214 | part1(graph); | 139 | part1(graph); |
| 215 | |||
| 216 | // print_graph(graph); | ||
| 217 | // cout << " ------------ " << endl; | ||
| 218 | // print_graph(get_rgraph(graph)); | ||
| 219 | // cout << " ------------ " << endl; | ||
| 220 | // print_graph(get_rgraph(get_rgraph(graph))); | ||
| 221 | |||
| 222 | // map<string, string> parents; | ||
| 223 | |||
| 224 | // if ( bfs(graph, "jqt", "bvb", parents) ) { | ||
| 225 | // for ( const auto& [lhs, rhs]: parents ) { | ||
| 226 | // cout << lhs << ": " << rhs << endl; | ||
| 227 | // } | ||
| 228 | // } | ||
| 229 | } | 140 | } |
