12 and 14
This commit is contained in:
parent
1dfe64b02d
commit
35e31bf67f
103
2019/12.cpp
Normal file
103
2019/12.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cinttypes>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <aocpp/Startup.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
struct Particle {
|
||||
std::int64_t pos;
|
||||
std::int64_t vel;
|
||||
auto operator==(Particle const& x) const -> bool = default;
|
||||
};
|
||||
|
||||
auto Step(std::vector<Particle> & ps) {
|
||||
// apply gravity to update velocities
|
||||
auto n = ps.size();
|
||||
for (int i = 0; i+1 < n; i++) {
|
||||
for (int j = i+1; j < n; j++) {
|
||||
auto v = (ps[i].pos < ps[j].pos) - (ps[i].pos > ps[j].pos);
|
||||
ps[i].vel += v;
|
||||
ps[j].vel -= v;
|
||||
}
|
||||
}
|
||||
// apply velocities to update positions
|
||||
for (auto & p : ps) {
|
||||
p.pos += p.vel;
|
||||
}
|
||||
}
|
||||
|
||||
auto CycleLength(std::vector<Particle> const& particles) -> std::int64_t {
|
||||
auto ps = particles;
|
||||
std::int64_t n = 0;
|
||||
do {
|
||||
Step(ps);
|
||||
n++;
|
||||
} while (!std::equal(ps.begin(), ps.end(), particles.begin()));
|
||||
return n;
|
||||
}
|
||||
|
||||
/// Parse input as a vector of particle systems by axis.
|
||||
auto Parse(std::istream & in) -> std::array<std::vector<Particle>,3> {
|
||||
std::array<std::vector<Particle>,3> result;
|
||||
std::string line;
|
||||
while (std::getline(in, line)) {
|
||||
std::int64_t x, y, z;
|
||||
auto res =
|
||||
std::sscanf(
|
||||
line.c_str(),
|
||||
"<x=%" SCNi64 ", y=%" SCNi64 ", z=%" SCNi64 ">",
|
||||
&x, &y, &z);
|
||||
if (3 != res) { throw std::runtime_error{"bad input"}; }
|
||||
result[0].push_back({x,0});
|
||||
result[1].push_back({y,0});
|
||||
result[2].push_back({z,0});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Compute part 1 by iterating the simulation step and compute the resulting
|
||||
/// system energy.
|
||||
auto Part1(std::array<std::vector<Particle>, 3> system, std::int64_t const n) {
|
||||
for (auto && ps : system) {
|
||||
for (std::int64_t i = 0; i < n; i++) { Step(ps); }
|
||||
}
|
||||
|
||||
std::int64_t result = 0;
|
||||
for (std::size_t i = 0; i < system[0].size(); i++) {
|
||||
std::int64_t xsum = 0;
|
||||
std::int64_t vsum = 0;
|
||||
for (auto && ps : system) {
|
||||
xsum += std::abs(ps[i].pos);
|
||||
vsum += std::abs(ps[i].vel);
|
||||
}
|
||||
result += xsum * vsum;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto Part2(std::array<std::vector<Particle>, 3> const& ps) {
|
||||
std::int64_t n = 1;
|
||||
for (auto && p : ps) {
|
||||
n = std::lcm(n, CycleLength(p));
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
auto main(int argc, char** argv) -> int {
|
||||
auto ps = Parse(aocpp::Startup(argc, argv));
|
||||
auto part2 = Part2(ps);
|
||||
auto part1 = Part1(std::move(ps), 1000);
|
||||
|
||||
std::cout << "Part 1: " << part1 << std::endl;
|
||||
std::cout << "Part 2: " << part2 << std::endl;
|
||||
}
|
147
2019/14.cpp
Normal file
147
2019/14.cpp
Normal file
|
@ -0,0 +1,147 @@
|
|||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
#include <aocpp/Startup.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
using Recipes = std::map<std::string, std::pair<std::int64_t, std::vector<std::pair<std::int64_t, std::string>>>>;
|
||||
|
||||
auto Parse(std::istream & in) -> Recipes {
|
||||
Recipes result;
|
||||
|
||||
std::string line;
|
||||
|
||||
std::int64_t n;
|
||||
std::string word;
|
||||
|
||||
while (std::getline(in, line)) {
|
||||
std::vector<std::pair<std::int64_t, std::string>> components;
|
||||
std::istringstream sin {line};
|
||||
|
||||
bool leftSide;
|
||||
do {
|
||||
sin >> n >> word;
|
||||
leftSide = word.back() == ',';
|
||||
if (leftSide) word.pop_back();
|
||||
components.push_back({n, word});
|
||||
} while(leftSide);
|
||||
sin >> word; // skip
|
||||
sin >> n >> word;
|
||||
result.insert({word, {n, std::move(components)}});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
auto Topsort(Recipes const& recipes) -> std::vector<std::string>
|
||||
{
|
||||
// Kahn's algorithm
|
||||
std::set<std::string> perm;
|
||||
std::set<std::string> temp;
|
||||
std::vector<std::string> result;
|
||||
|
||||
auto visit_ = [&](auto& rec, std::string name) -> void {
|
||||
if (!perm.contains(name)) {
|
||||
if (!temp.insert(name).second) throw std::runtime_error{"cyclic recipes"};
|
||||
if (recipes.contains(name)) {
|
||||
for (auto && [_, c] : recipes.at(name).second) {
|
||||
rec(rec, c);
|
||||
}
|
||||
}
|
||||
temp.erase(name);
|
||||
perm.insert(name);
|
||||
result.push_back(name);
|
||||
}
|
||||
};
|
||||
auto visit = [&](auto name) { visit_(visit_, name); };
|
||||
|
||||
for (auto && [k,_] : recipes) {
|
||||
visit(k);
|
||||
}
|
||||
|
||||
std::reverse(result.begin(), result.end());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
class Machine {
|
||||
struct Entry {
|
||||
std::int64_t need;
|
||||
std::int64_t batch;
|
||||
std::vector<std::pair<std::int64_t, std::int64_t&>> components;
|
||||
};
|
||||
std::int64_t ore_;
|
||||
std::vector<Entry> process_;
|
||||
public:
|
||||
Machine(Recipes const& recipes)
|
||||
{
|
||||
auto order = Topsort(recipes);
|
||||
order.pop_back();
|
||||
process_.resize(order.size(), {});
|
||||
|
||||
std::map<std::string, std::size_t> indexes;
|
||||
for (auto && name : order) {
|
||||
indexes.insert({name, indexes.size()});
|
||||
}
|
||||
|
||||
for (auto && [k,v] : recipes) {
|
||||
auto & entry = process_[indexes[k]];
|
||||
entry.batch = v.first;
|
||||
for (auto && [m,c] : v.second) {
|
||||
entry.components.push_back({m, c == "ORE" ? ore_ : process_[indexes[c]].need});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto operator()(std::int64_t fuel) {
|
||||
for (auto && entry : process_) {
|
||||
entry.need = 0;
|
||||
}
|
||||
process_[0].need = fuel;
|
||||
ore_ = 0;
|
||||
|
||||
for (auto && entry : process_) {
|
||||
auto batches = (entry.need + entry.batch - 1) / entry.batch;
|
||||
for (auto && [m,c] : entry.components) {
|
||||
c += batches*m;
|
||||
}
|
||||
}
|
||||
|
||||
return ore_;
|
||||
}
|
||||
};
|
||||
|
||||
auto ComputeFuel(Machine & machine, std::int64_t ore) {
|
||||
std::int64_t tooHi = 1;
|
||||
while (machine(tooHi) <= ore) {
|
||||
tooHi *= 2;
|
||||
}
|
||||
|
||||
std::int64_t lo = 0;
|
||||
while (lo+1 != tooHi) {
|
||||
auto mid = std::midpoint(lo, tooHi);
|
||||
(machine(mid) > ore ? tooHi : lo) = mid;
|
||||
}
|
||||
|
||||
return lo;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
auto main(int argc, char** argv) -> int {
|
||||
auto recipes = Parse(aocpp::Startup(argc, argv));
|
||||
auto machine = Machine(recipes);
|
||||
auto part1 = machine(1);
|
||||
auto part2 = ComputeFuel(machine, 1'000'000'000'000);
|
||||
std::cout << "Part 1: " << part1 << std::endl;
|
||||
std::cout << "Part 2: " << part2 << std::endl;
|
||||
}
|
|
@ -34,6 +34,9 @@ target_link_libraries(12 aocpp)
|
|||
add_executable(13 13.cpp)
|
||||
target_link_libraries(13 aocpp intcode)
|
||||
|
||||
add_executable(14 14.cpp)
|
||||
target_link_libraries(14 aocpp)
|
||||
|
||||
add_executable(15 15.cpp)
|
||||
target_link_libraries(15 aocpp intcode)
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user