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 phx = boost::phoenix;
|
||||||
namespace qi = boost::spirit::qi;
|
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.
|
/// @brief Array of distances from one node to another.
|
||||||
/// @tparam T distance type
|
/// @tparam T distance type
|
||||||
///
|
///
|
||||||
|
@ -55,15 +61,14 @@ auto ShortestDistances(distance_array<T> & dist) -> void
|
||||||
for (auto const k : range) {
|
for (auto const k : range) {
|
||||||
for (auto const i : range) {
|
for (auto const i : range) {
|
||||||
for (auto const j : range) {
|
for (auto const j : range) {
|
||||||
auto const new_dist = dist[i][k] + dist[k][j];
|
auto const d_ikj = dist[i][k] + dist[k][j];
|
||||||
auto & old_dist = dist[i][j];
|
auto & d_ij = dist[i][j];
|
||||||
if (old_dist > new_dist) old_dist = new_dist;
|
if (d_ij > d_ikj) d_ij = d_ijk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @struct Room
|
|
||||||
/// @brief A single record from the problem input.
|
/// @brief A single record from the problem input.
|
||||||
struct Room {
|
struct Room {
|
||||||
/// @brief Name of the room
|
/// @brief Name of the room
|
||||||
|
@ -122,7 +127,6 @@ auto FlowsFirst(
|
||||||
) -> std::size_t
|
) -> std::size_t
|
||||||
{
|
{
|
||||||
using namespace phx::placeholders;
|
using namespace phx::placeholders;
|
||||||
|
|
||||||
auto const zeros = boost::range::partition(rooms, phx::bind(&Room::flow, arg1) > 0);
|
auto const zeros = boost::range::partition(rooms, phx::bind(&Room::flow, arg1) > 0);
|
||||||
return std::distance(boost::begin(rooms), zeros);
|
return std::distance(boost::begin(rooms), zeros);
|
||||||
}
|
}
|
||||||
|
@ -134,7 +138,7 @@ auto GenerateDistances(
|
||||||
std::vector<Room> const& rooms
|
std::vector<Room> const& rooms
|
||||||
) -> std::pair<std::size_t, distance_array<std::uint64_t>>
|
) -> 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
|
// Associate the names and indexes of each room
|
||||||
std::unordered_map<std::string, std::size_t> names;
|
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]};
|
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())) {
|
for (auto const i : boost::irange(rooms.size())) {
|
||||||
auto & room = rooms[i];
|
|
||||||
auto di = distances[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
|
// 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;
|
di[names[name]] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,13 +165,12 @@ auto GenerateDistances(
|
||||||
|
|
||||||
ShortestDistances(distances);
|
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
|
/// @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
|
/// @brief Intermediate states for depth-first search in Routes
|
||||||
struct State {
|
struct State {
|
||||||
/// @brief Time remaining
|
/// @brief Time remaining
|
||||||
|
@ -194,11 +196,15 @@ auto Routes(
|
||||||
distance_array<std::uint64_t> const& distances
|
distance_array<std::uint64_t> const& distances
|
||||||
) -> std::unordered_map<Valves, std::uint64_t>
|
) -> 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
|
// Maximal flow seen at each set of open valves
|
||||||
std::unordered_map<Valves, std::uint64_t> result;
|
std::unordered_map<Valves, std::uint64_t> result;
|
||||||
|
|
||||||
// Remaining states for depth first search
|
// 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()) {
|
while (!states.empty()) {
|
||||||
auto const state = states.back();
|
auto const state = states.back();
|
||||||
states.pop_back();
|
states.pop_back();
|
||||||
|
@ -258,7 +264,7 @@ auto Part2(
|
||||||
{
|
{
|
||||||
auto const routes = Routes(start, 26, rooms, distances);
|
auto const routes = Routes(start, 26, rooms, distances);
|
||||||
auto const end = routes.end();
|
auto const end = routes.end();
|
||||||
|
|
||||||
std::uint64_t best {0};
|
std::uint64_t best {0};
|
||||||
for (auto it1 = routes.begin(); it1 != end; ++it1) {
|
for (auto it1 = routes.begin(); it1 != end; ++it1) {
|
||||||
for (auto it2 = std::next(it1); it2 != end; ++it2) {
|
for (auto it2 = std::next(it1); it2 != end; ++it2) {
|
||||||
|
@ -273,7 +279,7 @@ auto Part2(
|
||||||
|
|
||||||
} // namespace
|
} // 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] in input text
|
||||||
/// @param[in,out] out output text
|
/// @param[in,out] out output text
|
||||||
auto Main(std::istream & in, std::ostream & out) -> void
|
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][2] == 1);
|
||||||
CHECK(distances[3][3] == 0);
|
CHECK(distances[3][3] == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,12 +53,12 @@ namespace
|
||||||
case 't':
|
case 't':
|
||||||
result.run_tests = true;
|
result.run_tests = true;
|
||||||
break;
|
break;
|
||||||
case ':':
|
|
||||||
std::cerr << "Missing argument to -" << char(optopt) << std::endl;
|
|
||||||
return {};
|
|
||||||
case 'h':
|
case 'h':
|
||||||
result.print_help = true;
|
result.print_help = true;
|
||||||
break;
|
break;
|
||||||
|
case ':':
|
||||||
|
std::cerr << "Missing argument to -" << char(optopt) << std::endl;
|
||||||
|
return {};
|
||||||
case '?':
|
case '?':
|
||||||
default:
|
default:
|
||||||
std::cerr << "Unknown flag -" << char(optopt) << std::endl;
|
std::cerr << "Unknown flag -" << char(optopt) << std::endl;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user