#include #include #include #include #include #include #include #include #include constexpr auto OUT_OF_SERVICE_BUS = "x"; std::vector readInput(const std::string &filename) { std::vector input; std::string line; std::ifstream file(filename); while (std::getline(file, line)) { input.push_back(line); } return input; } /** * Parse a split list of bus times into a vector of pairs of the form * @param rawBusTimes The bus times to parse * @return std::vector> */ std::vector> parseBusTimes(const std::vector &rawBusTimes) { int nextBusOffsset = 0; // Holds both the bus time and its offset from the time t. std::vector> busTimes; busTimes.reserve(rawBusTimes.size()); for (auto it = rawBusTimes.cbegin(); it != rawBusTimes.cend(); (it++, nextBusOffsset++)) { auto rawBusTime = *it; if (rawBusTime == OUT_OF_SERVICE_BUS) { continue; } int busTime = std::stoi(rawBusTime); busTimes.emplace_back(busTime, nextBusOffsset); } return busTimes; } /** * Parse the puzzle input * @param input The input to parse * @return std::pair>> A pair of the form > */ std::pair>> parseInput(const std::vector &input) { int startTime = std::stoi(input.at(0)); const std::string &rawBusses = input.at(1); std::vector rawBusTimes; folly::split(",", rawBusses, rawBusTimes); auto parsedBusTimes = parseBusTimes(rawBusTimes); return std::pair>>(startTime, parsedBusTimes); } int part1(int busStartTime, const std::vector> &busTimes) { // Calculate the bus times that are immediately after the start time input std::map nextBusses; std::transform( busTimes.cbegin(), busTimes.cend(), std::inserter(nextBusses, nextBusses.end()), [busStartTime](const std::pair &busTime) { // Take the ceiling when dividing int numIntervals = (busTime.first + busStartTime - 1) / busTime.first; int nextBusTime = busTime.first * numIntervals; return std::pair(busTime.first, nextBusTime); }); auto minPairIterator = std::min_element( nextBusses.cbegin(), nextBusses.cend(), [](std::pair time1, std::pair time2) { return time1.second < time2.second; }); int bestBusID = minPairIterator->first; int bestBusTime = minPairIterator->second; int timeToWait = bestBusTime - busStartTime; return bestBusID * timeToWait; } long part2(const std::vector> &busTimes) { auto cursor = busTimes.cbegin(); long t = cursor->first; long stepSize = cursor->first; cursor++; while (cursor != busTimes.cend()) { t += stepSize; // Find the time that next bus that will start at the offset after t if ((t + cursor->second) % cursor->first != 0) { continue; } stepSize = std::lcm(stepSize, cursor->first); cursor++; } return t; } int main(int argc, char *argv[]) { if (argc != 2) { std::cerr << argv[0] << " " << std::endl; return 1; } auto input = readInput(argv[1]); auto parsedInput = parseInput(input); std::cout << part1(parsedInput.first, parsedInput.second) << std::endl; std::cout << part2(parsedInput.second) << std::endl; }