This commit is contained in:
Eric Mertens 2023-04-07 09:45:55 -07:00
parent 930a02622d
commit a38a105e6f
6 changed files with 62 additions and 39 deletions

View File

@ -2,6 +2,7 @@
#include <cstdint> #include <cstdint>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <stdexcept>
#include <variant> #include <variant>
#include <vector> #include <vector>

View File

@ -4,6 +4,7 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <stack> #include <stack>
#include <stdexcept>
#include <tuple> #include <tuple>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>

View File

@ -12,6 +12,7 @@
#include <cstdint> #include <cstdint>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <stack>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <tuple> #include <tuple>
@ -90,8 +91,8 @@ struct Room {
/// * Valve **name** has flow rate= **number** ; tunnel leads to valve **name** /// * Valve **name** has flow rate= **number** ; tunnel leads to valve **name**
auto Parse(std::istream & in) -> std::vector<Room> auto Parse(std::istream & in) -> std::vector<Room>
{ {
std::vector<Room> result; auto result = std::vector<Room>{};
std::string line; auto line = std::string{};
while (std::getline(in, line)) { while (std::getline(in, line)) {
using namespace qi::labels; using namespace qi::labels;
using It = std::string::const_iterator; using It = std::string::const_iterator;
@ -108,8 +109,8 @@ auto Parse(std::istream & in) -> std::vector<Room>
" " >> " " >>
(name % ", ") [ phx::bind(&Room::connections, _val) = _1 ]; (name % ", ") [ phx::bind(&Room::connections, _val) = _1 ];
It b = line.begin(); auto b = line.cbegin();
It const e = line.end(); auto const e = line.cend();
result.emplace_back(); result.emplace_back();
if (!qi::parse(b, e, room_description, result.back()) || b != e) { if (!qi::parse(b, e, room_description, result.back()) || b != e) {
throw std::runtime_error{"bad input line"}; throw std::runtime_error{"bad input line"};
@ -138,15 +139,15 @@ 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;
for (auto [i,room] : rooms | boost::adaptors::indexed()) { for (auto const [i,room] : boost::adaptors::index(rooms)) {
names[room.name] = i; names[room.name] = i;
} }
distance_array<std::uint64_t> distances{boost::extents[N][N]}; auto distances = distance_array<std::uint64_t>{boost::extents[N][N]};
for (auto const i : boost::irange(rooms.size())) { for (auto const i : boost::irange(rooms.size())) {
auto di = distances[i]; auto di = distances[i];
@ -201,13 +202,15 @@ auto Routes(
} }
// 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; auto result = std::unordered_map<Valves, std::uint64_t>{};
// Remaining states for depth first search // Remaining states for depth first search
std::vector<State> states {{initial_time, 0, start, {}}}; auto states = std::stack<State>{};
states.push({initial_time, 0, start, {}});
while (!states.empty()) { while (!states.empty()) {
auto const state = states.back(); auto const state = states.top();
states.pop_back(); states.pop();
if (auto & best = result[state.valves]; best < state.flow) { if (auto & best = result[state.valves]; best < state.flow) {
best = state.flow; best = state.flow;
@ -215,7 +218,7 @@ auto Routes(
auto const distances_i = distances[state.location]; auto const distances_i = distances[state.location];
for (auto const [j, room] : rooms | boost::adaptors::indexed()) { for (auto const [j, room] : boost::adaptors::index(rooms)) {
// don't revisit a valve // don't revisit a valve
if (state.valves.test(j)) { continue; } if (state.valves.test(j)) { continue; }
@ -229,7 +232,7 @@ auto Routes(
auto valves = state.valves; auto valves = state.valves;
valves.set(j); valves.set(j);
states.push_back({time, flow, static_cast<std::size_t>(j), valves}); states.push({time, flow, static_cast<std::size_t>(j), valves});
} }
} }
@ -265,7 +268,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}; auto best = std::uint64_t{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) {
// only consider pairs that have disjoint sets of valves // only consider pairs that have disjoint sets of valves
@ -285,7 +288,7 @@ auto Part2(
auto Main(std::istream & in, std::ostream & out) -> void auto Main(std::istream & in, std::ostream & out) -> void
{ {
auto rooms = Parse(in); auto rooms = Parse(in);
auto const n = FlowsFirst(rooms); auto const n = FlowsFirst(rooms); // reorders rooms
auto const [start, distances] = GenerateDistances(rooms); auto const [start, distances] = GenerateDistances(rooms);
rooms.resize(n); // forget about the rooms with no flow rooms.resize(n); // forget about the rooms with no flow
out << "Part 1: " << Part1(start, rooms, distances) << std::endl; out << "Part 1: " << Part1(start, rooms, distances) << std::endl;
@ -306,13 +309,13 @@ Valve HH has flow rate=22; tunnel leads to valve GG
Valve II has flow rate=0; tunnels lead to valves AA, JJ Valve II has flow rate=0; tunnels lead to valves AA, JJ
Valve JJ has flow rate=21; tunnel leads to valve II Valve JJ has flow rate=21; tunnel leads to valve II
)"}; )"};
std::ostringstream out; auto out = std::ostringstream{};
Main(in, out); Main(in, out);
CHECK(out.str() == "Part 1: 1651\nPart 2: 1707\n"); CHECK(out.str() == "Part 1: 1651\nPart 2: 1707\n");
} }
TEST_CASE("shortest path") { TEST_CASE("shortest path") {
distance_array<int> distances{boost::extents[4][4]}; auto distances = distance_array<int>{boost::extents[4][4]};
std::fill_n(distances.data(), distances.num_elements(), 100); std::fill_n(distances.data(), distances.num_elements(), 100);
distances[0][2] = -2; distances[0][2] = -2;

View File

@ -4,6 +4,7 @@
#include <iostream> #include <iostream>
#include <set> #include <set>
#include <sstream> #include <sstream>
#include <stack>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <tuple> #include <tuple>
@ -24,12 +25,14 @@ using Coord = aocpp::Vec<std::int64_t, 3>;
/// @return set of coordinates /// @return set of coordinates
auto Parse(std::istream & in) -> std::set<Coord> auto Parse(std::istream & in) -> std::set<Coord>
{ {
std::set<Coord> result; auto result = std::set<Coord>{};
std::string line; auto line = std::string{};
while (in >> line) { while (in >> line) {
Coord x; auto x = Coord{};
if (3 != std::sscanf(line.c_str(), "%lld,%lld,%lld\n", &x[0], &x[1], &x[2])) if (3 != std::sscanf(line.c_str(), "%lld,%lld,%lld\n", &x[0], &x[1], &x[2])) {
throw std::runtime_error{"bad input line"}; throw std::runtime_error{"bad input line"};
}
result.insert(x); result.insert(x);
} }
return result; return result;
@ -37,8 +40,8 @@ auto Parse(std::istream & in) -> std::set<Coord>
auto Part1(std::set<Coord> const& obj) -> std::size_t auto Part1(std::set<Coord> const& obj) -> std::size_t
{ {
std::size_t result {0}; auto result = std::size_t{0};
for (auto && x : obj) { for (auto const& x : obj) {
x.EachNeighbor([&](Coord const& y) { x.EachNeighbor([&](Coord const& y) {
if (!obj.contains(y)) result++; if (!obj.contains(y)) result++;
}); });
@ -49,21 +52,24 @@ auto Part1(std::set<Coord> const& obj) -> std::size_t
auto Part2(std::set<Coord> const& obj) -> std::size_t auto Part2(std::set<Coord> const& obj) -> std::size_t
{ {
auto [lo, hi] = Coord::BoundingBox(obj.begin(), obj.end()); auto [lo, hi] = Coord::BoundingBox(obj.begin(), obj.end());
lo -= Coord(1); lo -= Coord{1};
hi += Coord(1); hi += Coord{1};
std::set<Coord> seen {lo}; auto seen = std::set<Coord>{};
std::vector<Coord> work {lo}; auto work = std::stack<Coord>{};
std::size_t result {0}; auto result = std::size_t{0};
work.push(lo);
seen.insert(lo);
while (!work.empty()) { while (!work.empty()) {
auto x = work.back(); auto const x = work.top();
work.pop_back(); work.pop();
x.EachNeighbor([&, lo=lo, hi=hi](Coord const& y) { x.EachNeighbor([&, lo=lo, hi=hi](Coord const& y) {
if (obj.contains(y)) { if (obj.contains(y)) {
result++; result++;
} else if (y.InRange(lo, hi) && seen.insert(y).second) { } else if (y.InRange(lo, hi) && seen.insert(y).second) {
work.push_back(y); work.push(y);
} }
}); });
} }
@ -98,7 +104,7 @@ TEST_SUITE("2022-12 examples") {
auto Main(std::istream & in, std::ostream & out) -> void auto Main(std::istream & in, std::ostream & out) -> void
{ {
auto const obj {Parse(in)}; auto const obj = Parse(in);
out << "Part 1: " << Part1(obj) << std::endl; out << "Part 1: " << Part1(obj) << std::endl;
out << "Part 2: " << Part2(obj) << std::endl; out << "Part 2: " << Part2(obj) << std::endl;
} }

View File

@ -4,6 +4,7 @@
#include <iterator> #include <iterator>
#include <numeric> #include <numeric>
#include <sstream> #include <sstream>
#include <stdexcept>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
@ -24,7 +25,7 @@ using Input = std::vector<std::int64_t>;
/// @return outer list of elves, inner lists of calories /// @return outer list of elves, inner lists of calories
auto Parse(std::istream & in) -> Input auto Parse(std::istream & in) -> Input
{ {
Input result; auto result = Input{};
using It = std::istream_iterator<std::int64_t>; using It = std::istream_iterator<std::int64_t>;
std::copy<It>(in, {}, std::back_inserter(result)); std::copy<It>(in, {}, std::back_inserter(result));
return result; return result;
@ -33,7 +34,17 @@ auto Parse(std::istream & in) -> Input
auto Solve(Input const& input, std::size_t const rounds) -> std::int64_t auto Solve(Input const& input, std::size_t const rounds) -> std::int64_t
{ {
auto const len = input.size(); auto const len = input.size();
std::vector<std::size_t> fwds(len), bwds(len); auto fwds = std::vector<std::size_t>(len);
auto bwds = std::vector<std::size_t>(len);
if (len == 0) {
throw std::runtime_error{"Input too small"};
}
auto const zero_it = std::find(input.begin(), input.end(), 0);
if (zero_it == input.end()) {
throw std::runtime_error{"no zero element in input"};
}
std::iota(fwds.begin(), fwds.end()-1, 1); fwds.back() = 0; std::iota(fwds.begin(), fwds.end()-1, 1); fwds.back() = 0;
std::iota(bwds.begin()+1, bwds.end(), 0); bwds.front() = len-1; std::iota(bwds.begin()+1, bwds.end(), 0); bwds.front() = len-1;
@ -67,8 +78,8 @@ auto Solve(Input const& input, std::size_t const rounds) -> std::int64_t
} }
} }
std::int64_t sum {0}; auto sum = std::int64_t{0};
auto cursor = std::distance(input.begin(), std::find(input.begin(), input.end(), 0)); auto cursor = std::distance(input.begin(), zero_it);
for (auto const _ : boost::irange(3)) { for (auto const _ : boost::irange(3)) {
for (auto const _ : boost::irange(1000)) { for (auto const _ : boost::irange(1000)) {
cursor = fwds[cursor]; cursor = fwds[cursor];
@ -86,7 +97,7 @@ auto Part1(Input const& input) -> std::int64_t
auto Part2(Input input) -> std::int64_t auto Part2(Input input) -> std::int64_t
{ {
for (auto& x : input) { x *= 811589153; } for (auto& x : input) { x *= 811'589'153; }
return Solve(input, 10); return Solve(input, 10);
} }
@ -104,13 +115,13 @@ TEST_SUITE("2022-20 examples") {
"4\n"}; "4\n"};
auto input = Parse(in); auto input = Parse(in);
CHECK(3 == Part1(input)); CHECK(3 == Part1(input));
CHECK(1623178306 == Part2(input)); CHECK(1623178306 == Part2(std::move(input)));
} }
} }
auto Main(std::istream & in, std::ostream & out) -> void auto Main(std::istream & in, std::ostream & out) -> void
{ {
auto input {Parse(in)}; auto input = Parse(in);
out << "Part 1: " << Part1(input) << std::endl; out << "Part 1: " << Part1(input) << std::endl;
out << "Part 2: " << Part2(std::move(input)) << std::endl; out << "Part 2: " << Part2(std::move(input)) << std::endl;
} }

View File

@ -1,6 +1,7 @@
#include <cstdint> #include <cstdint>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <stdexcept>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <variant> #include <variant>