From 47b53be029910f12e7b76f17416b364795ec96a8 Mon Sep 17 00:00:00 2001 From: yut23 Date: Fri, 26 Jan 2024 23:07:50 -0500 Subject: [PATCH] 2023 day 23: speed up graph construction Preallocate a vector to hold neighbor positions, and simply clear it after use. Previously, about 50% of the time was spent allocating and deallocating temporary vectors. --- 2023/src/day23.hpp | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/2023/src/day23.hpp b/2023/src/day23.hpp index 72a80e2..53b58a2 100644 --- a/2023/src/day23.hpp +++ b/2023/src/day23.hpp @@ -37,8 +37,8 @@ class TrailMap { std::map> grid_prev; std::map, int> distances; - std::pair, bool> - get_grid_neighbors(const Pos &pos, const Pos &prev_pos) const; + bool get_grid_neighbors(const Pos &pos, const Pos &prev_pos, + std::vector &neighbors) const; void add_edge(const Pos &from, const Pos &to, int distance); void construct_trails(Pos start); @@ -73,23 +73,25 @@ TrailMap::TrailMap(const std::vector &grid_) : grid(grid_) { construct_trails(start); } -std::pair, bool> -TrailMap::get_grid_neighbors(const Pos &pos, const Pos &prev_pos) const { - std::vector neighbors; - +bool TrailMap::get_grid_neighbors(const Pos &pos, const Pos &prev_pos, + std::vector &neighbors) const { char terrain = grid[pos]; int neighbor_count = 0; switch (terrain) { case '#': - return {{}, false}; + break; case '>': - return {{pos + Delta(AbsDirection::east, true)}, false}; + neighbors.push_back(pos + Delta(AbsDirection::east, true)); + break; case '<': - return {{pos + Delta(AbsDirection::west, true)}, false}; + neighbors.push_back(pos + Delta(AbsDirection::west, true)); + break; case '^': - return {{pos + Delta(AbsDirection::north, true)}, false}; + neighbors.push_back(pos + Delta(AbsDirection::north, true)); + break; case 'v': - return {{pos + Delta(AbsDirection::south, true)}, false}; + neighbors.push_back(pos + Delta(AbsDirection::south, true)); + break; case '.': for (const auto dir : aoc::DIRECTIONS) { Pos new_pos = pos + Delta(dir, true); @@ -114,7 +116,7 @@ TrailMap::get_grid_neighbors(const Pos &pos, const Pos &prev_pos) const { assert(neighbors.size() <= 2); break; } - return {neighbors, neighbor_count > 2}; + return neighbor_count > 2; } void TrailMap::add_edge(const Pos &from, const Pos &to, int distance) { @@ -126,23 +128,28 @@ void TrailMap::add_edge(const Pos &from, const Pos &to, int distance) { void TrailMap::construct_trails(Pos start) { std::queue> pending; pending.emplace(start, start); + // allocate this once and reuse it, instead of allocating and deallocating + // inside the loop + std::vector neighbors; while (!pending.empty()) { auto [prev_pos, curr_pos] = pending.front(); start = prev_pos; pending.pop(); int length = prev_pos == curr_pos ? 0 : 1; while (true) { - const auto [neighbors, is_junction] = - get_grid_neighbors(curr_pos, prev_pos); + const bool is_junction = + get_grid_neighbors(curr_pos, prev_pos, neighbors); if (!is_junction && neighbors.size() == 1) { ++length; prev_pos = curr_pos; curr_pos = neighbors.front(); + neighbors.clear(); } else { // recurse on each of the outgoing paths (if any) for (const Pos &neighbor : neighbors) { pending.emplace(curr_pos, neighbor); } + neighbors.clear(); break; } }