16
This commit is contained in:
parent
586b3244a4
commit
57004e1a79
42
2022/16.cpp
42
2022/16.cpp
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user