This commit is contained in:
Eric Mertens 2023-02-01 11:23:04 -08:00
parent 586b3244a4
commit 57004e1a79
2 changed files with 27 additions and 21 deletions

View File

@ -34,6 +34,12 @@ namespace {
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;
/// @brief The starting room as defined in the problem statement
constexpr char const* STARTING_ROOM = "AA";
/// @brief Arbitrary number of valves this solution supports
constexpr std::size_t MAX_VALVES = 64;
/// @brief Array of distances from one node to another.
/// @tparam T distance type
///
@ -55,15 +61,14 @@ auto ShortestDistances(distance_array<T> & dist) -> void
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;
auto const d_ikj = dist[i][k] + dist[k][j];
auto & d_ij = dist[i][j];
if (d_ij > d_ikj) d_ij = d_ijk;
}
}
}
}
/// @struct Room
/// @brief A single record from the problem input.
struct Room {
/// @brief Name of the room
@ -122,7 +127,6 @@ auto FlowsFirst(
) -> std::size_t
{
using namespace phx::placeholders;
auto const zeros = boost::range::partition(rooms, phx::bind(&Room::flow, arg1) > 0);
return std::distance(boost::begin(rooms), zeros);
}
@ -134,7 +138,7 @@ auto GenerateDistances(
std::vector<Room> const& rooms
) -> std::pair<std::size_t, distance_array<std::uint64_t>>
{
auto const N = rooms.size();
auto const N {rooms.size()};
// Associate the names and indexes of each room
std::unordered_map<std::string, std::size_t> names;
@ -144,15 +148,14 @@ auto GenerateDistances(
distance_array<std::uint64_t> distances{boost::extents[N][N]};
// N is longer than any optimal distance by at least 1
std::fill_n(distances.data(), distances.num_elements(), N);
for (auto const i : boost::irange(rooms.size())) {
auto & room = rooms[i];
auto di = distances[i];
// Default value: N is longer than any optimal distance by at least 1
boost::range::fill(di, N);
// each room is one away from adjacent rooms
for (auto const& name : room.connections) {
for (auto const& name : rooms[i].connections) {
di[names[name]] = 1;
}
@ -162,13 +165,12 @@ auto GenerateDistances(
ShortestDistances(distances);
return {names.at("AA"), std::move(distances)};
return {names.at(STARTING_ROOM), std::move(distances)};
}
/// @brief Bitset used to track which valves have been turned on
using Valves = std::bitset<64>;
using Valves = std::bitset<MAX_VALVES>;
/// @struct State
/// @brief Intermediate states for depth-first search in Routes
struct State {
/// @brief Time remaining
@ -194,11 +196,15 @@ auto Routes(
distance_array<std::uint64_t> const& distances
) -> std::unordered_map<Valves, std::uint64_t>
{
if (rooms.size() > MAX_VALVES) {
throw std::runtime_error{"Too many valves"};
}
// Maximal flow seen at each set of open valves
std::unordered_map<Valves, std::uint64_t> result;
// Remaining states for depth first search
std::vector<State> states { State{initial_time, 0, start, {}} };
std::vector<State> states {{initial_time, 0, start, {}}};
while (!states.empty()) {
auto const state = states.back();
states.pop_back();
@ -258,7 +264,7 @@ auto Part2(
{
auto const routes = Routes(start, 26, rooms, distances);
auto const end = routes.end();
std::uint64_t best {0};
for (auto it1 = routes.begin(); it1 != end; ++it1) {
for (auto it2 = std::next(it1); it2 != end; ++it2) {
@ -273,7 +279,7 @@ auto Part2(
} // namespace
/// @brief Print solutions to parts 1 and 2
/// @brief Print solutions to parts 1 and 2
/// @param[in,out] in input text
/// @param[in,out] out output text
auto Main(std::istream & in, std::ostream & out) -> void
@ -340,4 +346,4 @@ Valve JJ has flow rate=21; tunnel leads to valve II
CHECK(distances[3][2] == 1);
CHECK(distances[3][3] == 0);
}
}
}

View File

@ -53,12 +53,12 @@ namespace
case 't':
result.run_tests = true;
break;
case ':':
std::cerr << "Missing argument to -" << char(optopt) << std::endl;
return {};
case 'h':
result.print_help = true;
break;
case ':':
std::cerr << "Missing argument to -" << char(optopt) << std::endl;
return {};
case '?':
default:
std::cerr << "Unknown flag -" << char(optopt) << std::endl;