#include #include #include #include #include #include #include #include #include #include #include #include #include namespace { auto ShortestDistances(std::vector> & dist) { auto const range = boost::irange(dist.size()); for (auto const k : range) { for (auto const i : range) { for (auto const j : range) { auto const new_dist = dist[i][k] + dist[k][j]; auto & old_dist = dist[i][j]; if (old_dist > new_dist) old_dist = new_dist; } } } } struct RawRoom { std::string name; std::uint64_t flow; std::vector connections; }; struct Room { std::uint64_t flow; std::vector connections; }; auto Parse(std::istream & in) -> std::vector { std::vector result; std::string line; while (std::getline(in, line)) { RawRoom room; using namespace boost::spirit; auto const name = qi::as_string[+qi::alpha]; auto const room_description = "Valve " >> name [ ([&](auto n) { room.name = n; }) ] >> " has flow rate=" >> qi::ulong_long [ ([&](auto f) { room.flow = f; }) ] >> "; tunnel" >> -qi::string("s") >> " lead" >> -qi::string("s") >> " to valve" >> -qi::string("s") >> " " >> (name % ", ") [ ([&](auto c) { room.connections = c; }) ]; if (!qi::parse(line.begin(), line.end(), room_description)) { throw std::runtime_error{"bad input line"}; } result.emplace_back(std::move(room)); } return result; } auto GenerateGraph(std::vector const& raw_rooms) -> std::vector { std::vector result; std::map names; std::vector> distances( raw_rooms.size(), std::vector(raw_rooms.size(), 100)); // todo max limit for (auto const i : boost::irange(raw_rooms.size())) { names[raw_rooms[i].name] = i; } for (auto const i : boost::irange(raw_rooms.size())) { auto & ds = distances[i]; for (auto const& name : raw_rooms[i].connections) { ds[names[name]] = 1; } } ShortestDistances(distances); for (auto const i : boost::irange(raw_rooms.size())) { result.push_back({raw_rooms[i].flow, std::move(distances[i])}); } return result; } using Valves = std::bitset<64>; struct State { std::uint64_t time; std::uint64_t flow; std::size_t location; Valves valves; }; auto Routes(std::vector const& rooms, std::uint64_t time) -> std::map { std::vector states { State{time, 0, 0, {}} }; std::map result; while (!states.empty()) { auto state = states.back(); states.pop_back(); auto const& room = rooms[state.location]; for (auto const i : boost::irange(rooms.size())) { auto valves = state.valves; if (valves[i]) { continue; } auto const flow = rooms[i].flow; if (flow == 0) { continue; } auto const cost = room.connections[i]; if (cost >= state.time) { continue; } auto const time_ = state.time - cost - 1; valves[i] = true; auto const flow_ = state.flow + time_; if (result[valves.to_ullong()] < flow_) { result[valves.to_ullong()] = flow_; } states.push_back({ time_, state.flow + time_, i, valves}); } } return result; } } // namespace TEST_SUITE("2022-16 examples") { TEST_CASE("example") { std::istringstream in { }; } } auto main(int argc, char** argv) -> int { auto const input = Parse(*aocpp::Startup(argc, argv)); auto const graph = GenerateGraph(input); auto const routes = Routes(graph, 30); std::uint64_t p1 = 0; for (auto const& kv : routes) { p1 = std::max(p1, kv.second); } std::cout << "Part 1: " << p1 << std::endl; //Part2(snapshots, std::cout << "Part 2:\n"); }