From 48da2e2805dd56932674e709f28d70836aac499d Mon Sep 17 00:00:00 2001 From: Eric Mertens Date: Wed, 9 Nov 2022 15:45:55 -0800 Subject: [PATCH] fewer lookups in kahn's algorithm --- 2019/14.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/2019/14.cpp b/2019/14.cpp index 571dd91..74779e2 100644 --- a/2019/14.cpp +++ b/2019/14.cpp @@ -45,27 +45,30 @@ auto Parse(std::istream & in) -> Recipes { auto Topsort(Recipes const& recipes) -> std::vector { // Kahn's algorithm - std::set perm; - std::set temp; std::vector result; + result.reserve(recipes.size()); - auto visit_ = [&](auto& rec, std::string name) -> void { - if (!perm.contains(name)) { - if (!temp.insert(name).second) throw std::runtime_error{"cyclic recipes"}; - if (recipes.contains(name)) { - for (auto && [_, c] : recipes.at(name).second) { - rec(rec, c); + std::map marks; // false temp, true done + auto const visit = [&](auto const& visit, auto const& name) -> void { + auto [mark_iterator, is_new] = marks.try_emplace(name, false); + auto& [_, is_done] = *mark_iterator; + + if (is_new) { + auto const rit = recipes.find(name); + if (rit != recipes.end()) { + for (auto const& [_, c] : rit->second.second) { + visit(visit, c); } } - temp.erase(name); - perm.insert(name); + is_done = true; result.push_back(name); + } else if (!is_done) { + throw std::runtime_error{"cyclic graph"}; } }; - auto visit = [&](auto name) { visit_(visit_, name); }; - for (auto && [k,_] : recipes) { - visit(k); + for (auto const& [c,_] : recipes) { + visit(visit, c); } std::reverse(result.begin(), result.end());