Day 2022-16 tidied up.
This commit is contained in:
@@ -6,15 +6,13 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <numeric>
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using Int = std::int64_t;
|
using UInt = std::uint32_t;
|
||||||
using UInt = std::uint64_t;
|
|
||||||
|
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
@@ -59,18 +57,26 @@ struct State
|
|||||||
ValveID id_[2]{ValveID("AA"s), ValveID("AA"s)};
|
ValveID id_[2]{ValveID("AA"s), ValveID("AA"s)};
|
||||||
UInt next_time_[2]{26, 26};
|
UInt next_time_[2]{26, 26};
|
||||||
UInt total_rate_{0};
|
UInt total_rate_{0};
|
||||||
std::vector<char> open_{std::vector<char>(ValveID::max(), false)};
|
std::vector<char> open_{std::vector<char>(ValveID::max(), 0)};
|
||||||
|
|
||||||
auto operator<=>(State const& rhs) const noexcept -> std::strong_ordering
|
auto operator<=>(State const& rhs) const noexcept -> std::strong_ordering
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < 2; ++i) {
|
/* For comparisons - we don't care whether the human or elephant is at each site - only that one
|
||||||
if (id_[i] != rhs.id_[i]) {
|
* of them is. So we compare the max and min
|
||||||
return id_[i] <=> rhs.id_[i];
|
*/
|
||||||
}
|
auto lm1{std::max(id_[0], id_[1])};
|
||||||
if (next_time_[i] != rhs.next_time_[i]) {
|
auto rm1{std::max(rhs.id_[0], rhs.id_[1])};
|
||||||
return next_time_[i] <=> rhs.next_time_[i];
|
auto lm2{std::min(id_[0], id_[1])};
|
||||||
|
auto rm2{std::min(rhs.id_[0], rhs.id_[1])};
|
||||||
|
if (lm1 != rm1) {
|
||||||
|
return lm1 <=> rm1;
|
||||||
}
|
}
|
||||||
|
if (lm2 != rm2) {
|
||||||
|
return lm2 <=> rm2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We do not care about the time left or the score for sorting. */
|
||||||
|
|
||||||
for (UInt i{0}; i < open_.size(); ++i) {
|
for (UInt i{0}; i < open_.size(); ++i) {
|
||||||
if (open_[i] != rhs.open_[i]) {
|
if (open_[i] != rhs.open_[i]) {
|
||||||
return open_[i] <=> rhs.open_[i];
|
return open_[i] <=> rhs.open_[i];
|
||||||
@@ -85,9 +91,12 @@ auto main() -> int
|
|||||||
std::string line;
|
std::string line;
|
||||||
std::regex const re{
|
std::regex const re{
|
||||||
"Valve ([A-Z][A-Z]) has flow rate=(\\d+); tunnels? leads? to valves? ([A-Z, ]+)"};
|
"Valve ([A-Z][A-Z]) has flow rate=(\\d+); tunnels? leads? to valves? ([A-Z, ]+)"};
|
||||||
|
|
||||||
|
/* The edges vector will end up so that edges[a][b] will contain the number of seconds it will
|
||||||
|
* take to go from a to b, or 0 if there are no routes, or it is not worth stopping at b.
|
||||||
|
*/
|
||||||
std::vector<std::vector<UInt>> edges(ValveID::max(), std::vector<UInt>(ValveID::max(), 0));
|
std::vector<std::vector<UInt>> edges(ValveID::max(), std::vector<UInt>(ValveID::max(), 0));
|
||||||
std::vector<UInt> rates(ValveID::max(), 0);
|
std::vector<UInt> rates(ValveID::max(), 0);
|
||||||
UInt size{0};
|
|
||||||
|
|
||||||
while (std::getline(std::cin, line)) {
|
while (std::getline(std::cin, line)) {
|
||||||
std::smatch m;
|
std::smatch m;
|
||||||
@@ -110,6 +119,9 @@ auto main() -> int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* edges currently contains all routes that are one step away. Now update it so that all possible
|
||||||
|
* moves are possible.
|
||||||
|
*/
|
||||||
bool changed{true};
|
bool changed{true};
|
||||||
while (changed) {
|
while (changed) {
|
||||||
changed = false;
|
changed = false;
|
||||||
@@ -127,12 +139,12 @@ auto main() -> int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turning default state on.
|
// Moves from `a` to `a` are worthless.
|
||||||
for (UInt id{0}; id < ValveID::max(); ++id) {
|
for (UInt id{0}; id < ValveID::max(); ++id) {
|
||||||
edges[id][id] = 0;
|
edges[id][id] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If rate at a site is zero then change the cost to zero.
|
// If rate at a site is zero then change the cost to zero, as there is no point stopping here.
|
||||||
for (UInt e1{0}; e1 < ValveID::max(); ++e1) {
|
for (UInt e1{0}; e1 < ValveID::max(); ++e1) {
|
||||||
for (UInt e2{0}; e2 < ValveID::max(); ++e2) {
|
for (UInt e2{0}; e2 < ValveID::max(); ++e2) {
|
||||||
if (rates[e2] == 0) {
|
if (rates[e2] == 0) {
|
||||||
@@ -156,15 +168,18 @@ auto main() -> int
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::list<State> next_states;
|
||||||
for (auto it{current_states.begin()}; it != current_states.end();) {
|
for (auto it{current_states.begin()}; it != current_states.end();) {
|
||||||
|
// Is it the current time to modify this item?
|
||||||
if (it->next_time_[mover] != time_left) {
|
if (it->next_time_[mover] != time_left) {
|
||||||
++it;
|
++it;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValveID from{it->id_[mover]};
|
ValveID const from{it->id_[mover]};
|
||||||
|
|
||||||
for (UInt to{0}; to < ValveID::max(); ++to) {
|
for (UInt to{0}; to < ValveID::max(); ++to) {
|
||||||
|
// Determine were to move to.
|
||||||
if (edges[from][to] == 0) {
|
if (edges[from][to] == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -177,12 +192,14 @@ auto main() -> int
|
|||||||
|
|
||||||
State next_state{*it};
|
State next_state{*it};
|
||||||
next_state.id_[mover] = ValveID(to);
|
next_state.id_[mover] = ValveID(to);
|
||||||
next_state.open_[to] = true;
|
next_state.open_[to] = 1;
|
||||||
auto timestep = edges[from][to] + 1;
|
auto const time_step{edges[from][to] + 1};
|
||||||
next_state.next_time_[mover] -= timestep;
|
next_state.next_time_[mover] -= time_step;
|
||||||
next_state.total_rate_ += (next_state.next_time_[mover]) * rates[to];
|
next_state.total_rate_ += (next_state.next_time_[mover]) * rates[to];
|
||||||
best_rate = std::max(best_rate, next_state.total_rate_);
|
best_rate = std::max(best_rate, next_state.total_rate_);
|
||||||
|
|
||||||
|
// Ensure that this is going to make things better: Either we've never visited the state
|
||||||
|
// before. Or if we have then this version has a higher score.
|
||||||
auto vit = visited_states.find(next_state);
|
auto vit = visited_states.find(next_state);
|
||||||
if (vit != visited_states.end() && vit->total_rate_ >= next_state.total_rate_) {
|
if (vit != visited_states.end() && vit->total_rate_ >= next_state.total_rate_) {
|
||||||
continue;
|
continue;
|
||||||
@@ -191,10 +208,11 @@ auto main() -> int
|
|||||||
visited_states.erase(vit);
|
visited_states.erase(vit);
|
||||||
}
|
}
|
||||||
visited_states.insert(next_state);
|
visited_states.insert(next_state);
|
||||||
current_states.push_back(next_state);
|
next_states.push_back(next_state);
|
||||||
}
|
}
|
||||||
it = current_states.erase(it);
|
it = current_states.erase(it);
|
||||||
}
|
}
|
||||||
|
current_states.splice(current_states.end(), next_states);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user