Add 2021 day 15 puzzles
This commit is contained in:
81
2021/puzzle-15-01.cc
Normal file
81
2021/puzzle-15-01.cc
Normal file
@@ -0,0 +1,81 @@
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using UInt = unsigned int;
|
||||
|
||||
struct Cost
|
||||
{
|
||||
constexpr explicit Cost(UInt entry_cost) : entry_cost_(entry_cost) {}
|
||||
|
||||
[[nodiscard]] constexpr auto entry_cost() const noexcept -> UInt { return entry_cost_; }
|
||||
[[nodiscard]] constexpr auto total_cost() const noexcept -> UInt { return total_cost_; }
|
||||
[[nodiscard]] constexpr auto visited() const noexcept -> bool { return visited_; }
|
||||
|
||||
constexpr void total_cost(UInt total_cost) noexcept { total_cost_ = total_cost; }
|
||||
constexpr void update_total_cost(UInt v) noexcept
|
||||
{
|
||||
total_cost_ = std::min(entry_cost_ + v, total_cost_);
|
||||
}
|
||||
constexpr void visit() noexcept { visited_ = true; }
|
||||
|
||||
private:
|
||||
UInt entry_cost_;
|
||||
UInt total_cost_{std::numeric_limits<UInt>::max()};
|
||||
bool visited_{false};
|
||||
};
|
||||
|
||||
using CostVector = std::vector<Cost>;
|
||||
|
||||
auto main() -> int
|
||||
{
|
||||
std::string line;
|
||||
CostVector costs;
|
||||
UInt width{0};
|
||||
while (std::getline(std::cin, line) && !line.empty()) {
|
||||
if (width == 0) {
|
||||
width = line.size();
|
||||
}
|
||||
else {
|
||||
assert(width == line.size());
|
||||
}
|
||||
for (auto c : line) {
|
||||
costs.emplace_back(c - '0');
|
||||
}
|
||||
}
|
||||
|
||||
costs[0].total_cost(0);
|
||||
|
||||
while (true) {
|
||||
/* Note that the comparison below makes deliberate use of unsigned wrap-round. */
|
||||
auto it{costs.begin()};
|
||||
UInt cost{std::numeric_limits<UInt>::max()};
|
||||
for (auto it2{costs.begin()}; it2 != costs.end(); ++it2) {
|
||||
if (!it2->visited() && it2->total_cost() < cost) {
|
||||
cost = it2->total_cost();
|
||||
it = it2;
|
||||
}
|
||||
}
|
||||
it->visit();
|
||||
auto current_cost{it->total_cost()};
|
||||
auto idx{std::distance(costs.begin(), it)};
|
||||
if (idx == costs.size() - 1) {
|
||||
std::cout << "Total cost: " << current_cost;
|
||||
return 0;
|
||||
}
|
||||
if (idx % width != 0) {
|
||||
costs.at(idx - 1).update_total_cost(current_cost);
|
||||
}
|
||||
if ((idx + 1) % width != 0) {
|
||||
costs.at(idx + 1).update_total_cost(current_cost);
|
||||
}
|
||||
if (idx > width) {
|
||||
costs.at(idx - width).update_total_cost(current_cost);
|
||||
}
|
||||
if (idx + width < costs.size()) {
|
||||
costs.at(idx + width).update_total_cost(current_cost);
|
||||
}
|
||||
}
|
||||
}
|
97
2021/puzzle-15-02.cc
Normal file
97
2021/puzzle-15-02.cc
Normal file
@@ -0,0 +1,97 @@
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using UInt = unsigned int;
|
||||
|
||||
struct Cost
|
||||
{
|
||||
constexpr explicit Cost(UInt entry_cost) : entry_cost_(entry_cost) {}
|
||||
|
||||
[[nodiscard]] constexpr auto entry_cost() const noexcept -> UInt { return entry_cost_; }
|
||||
[[nodiscard]] constexpr auto total_cost() const noexcept -> UInt { return total_cost_; }
|
||||
[[nodiscard]] constexpr auto visited() const noexcept -> bool { return visited_; }
|
||||
|
||||
constexpr void total_cost(UInt total_cost) noexcept { total_cost_ = total_cost; }
|
||||
constexpr void update_total_cost(UInt v) noexcept
|
||||
{
|
||||
total_cost_ = std::min(entry_cost_ + v, total_cost_);
|
||||
}
|
||||
constexpr void visit() noexcept { visited_ = true; }
|
||||
|
||||
private:
|
||||
UInt entry_cost_;
|
||||
UInt total_cost_{std::numeric_limits<UInt>::max()};
|
||||
bool visited_{false};
|
||||
};
|
||||
|
||||
using CostVector = std::vector<Cost>;
|
||||
|
||||
auto main() -> int
|
||||
{
|
||||
std::string line;
|
||||
CostVector costs;
|
||||
UInt width{0};
|
||||
while (std::getline(std::cin, line) && !line.empty()) {
|
||||
if (width == 0) {
|
||||
width = line.size();
|
||||
}
|
||||
else {
|
||||
assert(width == line.size());
|
||||
}
|
||||
for (unsigned i{0}; i < 5; ++i) {
|
||||
for (auto c : line) {
|
||||
UInt cost{c - '0' + i};
|
||||
if (cost > 9) {
|
||||
cost -= 9;
|
||||
}
|
||||
costs.emplace_back(cost);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto initial_size{costs.size()};
|
||||
auto target_size{initial_size * 5};
|
||||
for (auto i{initial_size}; i < target_size; ++i) {
|
||||
auto cost{costs[i - initial_size].entry_cost() + 1};
|
||||
if (cost > 9) {
|
||||
cost -= 9;
|
||||
}
|
||||
costs.emplace_back(cost);
|
||||
}
|
||||
|
||||
costs[0].total_cost(0);
|
||||
width *= 5;
|
||||
|
||||
while (true) {
|
||||
/* Note that the comparison below makes deliberate use of unsigned wrap-round. */
|
||||
auto it{costs.begin()};
|
||||
UInt cost{std::numeric_limits<UInt>::max()};
|
||||
for (auto it2{costs.begin()}; it2 != costs.end(); ++it2) {
|
||||
if (!it2->visited() && it2->total_cost() < cost) {
|
||||
cost = it2->total_cost();
|
||||
it = it2;
|
||||
}
|
||||
}
|
||||
it->visit();
|
||||
auto current_cost{it->total_cost()};
|
||||
auto idx{std::distance(costs.begin(), it)};
|
||||
if (idx == costs.size() - 1) {
|
||||
std::cout << "Total cost: " << current_cost;
|
||||
return 0;
|
||||
}
|
||||
if (idx % width != 0) {
|
||||
costs[idx - 1].update_total_cost(current_cost);
|
||||
}
|
||||
if ((idx + 1) % width != 0) {
|
||||
costs[idx + 1].update_total_cost(current_cost);
|
||||
}
|
||||
if (idx > width) {
|
||||
costs[idx - width].update_total_cost(current_cost);
|
||||
}
|
||||
if (idx + width < costs.size()) {
|
||||
costs[idx + width].update_total_cost(current_cost);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user