16
This commit is contained in:
parent
94f5cb3eb4
commit
542ccc7884
43
2022/16.cpp
43
2022/16.cpp
@ -31,6 +31,9 @@
|
||||
|
||||
namespace {
|
||||
|
||||
namespace phx = boost::phoenix;
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
/// @brief Array of distances from one node to another.
|
||||
/// @tparam T distance type
|
||||
///
|
||||
@ -85,8 +88,6 @@ auto Parse(std::istream & in) -> std::vector<Room>
|
||||
std::vector<Room> result;
|
||||
std::string line;
|
||||
while (std::getline(in, line)) {
|
||||
namespace phx = boost::phoenix;
|
||||
namespace qi = boost::spirit::qi;
|
||||
using namespace qi::labels;
|
||||
using It = std::string::const_iterator;
|
||||
|
||||
@ -120,8 +121,10 @@ auto FlowsFirst(
|
||||
std::vector<Room> & rooms
|
||||
) -> std::size_t
|
||||
{
|
||||
auto const zeros = boost::range::partition(rooms, [](auto const& room) { return room.flow > 0; });
|
||||
return zeros - rooms.begin();
|
||||
using namespace phx::placeholders;
|
||||
|
||||
auto const zeros = boost::range::partition(rooms, phx::bind(&Room::flow, arg1) > 0);
|
||||
return std::distance(boost::begin(rooms), zeros);
|
||||
}
|
||||
|
||||
/// @brief Computes the distances between rooms and finds the address of the starting room
|
||||
@ -144,7 +147,8 @@ auto GenerateDistances(
|
||||
// N is longer than any optimal distance by at least 1
|
||||
std::fill_n(distances.data(), distances.num_elements(), N);
|
||||
|
||||
for (auto [i, room] : rooms | boost::adaptors::indexed()) {
|
||||
for (auto const i : boost::irange(rooms.size())) {
|
||||
auto & room = rooms[i];
|
||||
auto di = distances[i];
|
||||
|
||||
// each room is one away from adjacent rooms
|
||||
@ -185,7 +189,6 @@ struct State {
|
||||
/// @return Mapping of maximum flow achievable using a particular set of valves
|
||||
auto Routes(
|
||||
std::size_t const start,
|
||||
std::size_t const interesting,
|
||||
std::uint64_t const initial_time,
|
||||
std::vector<Room> const& rooms,
|
||||
distance_array<std::uint64_t> const& distances
|
||||
@ -206,7 +209,7 @@ auto Routes(
|
||||
|
||||
auto const distances_i = distances[state.location];
|
||||
|
||||
for (auto const j : boost::irange(interesting)) {
|
||||
for (auto const [j, room] : rooms | boost::adaptors::indexed()) {
|
||||
// don't revisit a valve
|
||||
if (state.valves.test(j)) { continue; }
|
||||
|
||||
@ -216,7 +219,7 @@ auto Routes(
|
||||
if (cost >= state.time) { continue; }
|
||||
|
||||
auto const time = state.time - cost;
|
||||
auto const flow = state.flow + rooms[j].flow * time;
|
||||
auto const flow = state.flow + room.flow * time;
|
||||
auto valves = state.valves;
|
||||
valves.set(j);
|
||||
|
||||
@ -234,33 +237,31 @@ auto Routes(
|
||||
/// @return Maximum flow achievable
|
||||
auto Part1(
|
||||
std::size_t const start,
|
||||
std::size_t const interesting,
|
||||
std::vector<Room> const& rooms,
|
||||
distance_array<std::uint64_t> const& distances
|
||||
) -> std::uint64_t
|
||||
{
|
||||
auto const routes = Routes(start, interesting, 30, rooms, distances);
|
||||
auto const routes = Routes(start, 30, rooms, distances);
|
||||
return *boost::range::max_element(routes | boost::adaptors::map_values);
|
||||
}
|
||||
|
||||
/// @brief Maximize the water flow using two actos and 26 minutes
|
||||
/// @brief Maximize the water flow using two actors and 26 minutes
|
||||
/// @param[in] start Index of the starting room
|
||||
/// @param[in] rooms Rooms from input file
|
||||
/// @param[in] distances Shortest distances between pairs of rooms
|
||||
/// @return Maximum flow achievable
|
||||
auto Part2(
|
||||
std::size_t const start,
|
||||
std::size_t const interesting,
|
||||
std::vector<Room> const& rooms,
|
||||
distance_array<std::uint64_t> const& distances
|
||||
) -> std::uint64_t
|
||||
{
|
||||
auto const routes = Routes(start, interesting, 26, rooms, distances);
|
||||
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; std::advance(it1, 1)) {
|
||||
for (auto it2 = std::next(it1); it2 != end; std::advance(it2, 1)) {
|
||||
for (auto it1 = routes.begin(); it1 != end; ++it1) {
|
||||
for (auto it2 = std::next(it1); it2 != end; ++it2) {
|
||||
// only consider pairs that have disjoint sets of valves
|
||||
if ((it1->first & it2->first).none()) {
|
||||
best = std::max(best, it1->second + it2->second);
|
||||
@ -287,10 +288,11 @@ Valve II has flow rate=0; tunnels lead to valves AA, JJ
|
||||
Valve JJ has flow rate=21; tunnel leads to valve II
|
||||
)"};
|
||||
auto rooms = Parse(in);
|
||||
auto const interesting = FlowsFirst(rooms);
|
||||
auto const n = FlowsFirst(rooms);
|
||||
auto const [start, distances] = GenerateDistances(rooms);
|
||||
CHECK(1651 == Part1(start, interesting, rooms, distances));
|
||||
CHECK(1707 == Part2(start, interesting, rooms, distances));
|
||||
rooms.resize(n);
|
||||
CHECK(1651 == Part1(start, rooms, distances));
|
||||
CHECK(1707 == Part2(start, rooms, distances));
|
||||
}
|
||||
|
||||
TEST_CASE("shortest path") {
|
||||
@ -339,6 +341,7 @@ auto main(int argc, char** argv) -> int
|
||||
auto rooms = Parse(*aocpp::Startup(argc, argv));
|
||||
auto const n = FlowsFirst(rooms);
|
||||
auto const [start, distances] = GenerateDistances(rooms);
|
||||
std::cout << "Part 1: " << Part1(start, n, rooms, distances) << std::endl;
|
||||
std::cout << "Part 2: " << Part2(start, n, rooms, distances) << std::endl;
|
||||
rooms.resize(n);
|
||||
std::cout << "Part 1: " << Part1(start, rooms, distances) << std::endl;
|
||||
std::cout << "Part 2: " << Part2(start, rooms, distances) << std::endl;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user