AdventOfCode2024/Aufgabe 5/main.cpp

238 lines
7.1 KiB
C++
Raw Permalink Normal View History

2024-12-11 18:20:32 +00:00
#include <iostream>
#include <vector>
#include <fstream>
#include <unordered_map>
#include <unordered_set>
#include <queue>
2024-12-11 20:35:13 +00:00
#include <omp.h>
2024-12-11 18:20:32 +00:00
struct Rule{
int first;
int second;
Rule(int first, int second) : first(first), second(second) {}
};
struct Update {
std::vector<int> pages;
explicit Update(const std::vector<int> &pages) : pages(pages) {}
};
std::vector<std::string> readTextFromFile(const std::string& fileName) {
std::vector<std::string> lines;
std::ifstream file(fileName);
if (!file) { // Überprüft, ob die Datei geöffnet werden konnte
std::cerr << "Fehler: Datei konnte nicht geöffnet werden: " << fileName << std::endl;
return lines;
}
std::string s;
while(getline(file, s)) {
lines.push_back(s);
}
return lines;
}
std::vector<std::string> splitString(const std::string& input, char ch) {
std::vector<std::string> splittedString;
size_t pos = input.find(ch);
size_t initialPos = 0;
while(pos != std::string::npos) {
splittedString.push_back(input.substr(initialPos, pos - initialPos));
initialPos = pos + 1;
pos = input.find(ch, initialPos);
}
splittedString.push_back(input.substr(initialPos, std::min(pos, input.size()) - initialPos));
return splittedString;
}
std::vector<Rule> parseRules(std::vector<std::string>& input) {
std::vector<Rule> rules;
for(const auto& line : input) {
if(line.find('|') != std::string::npos) {
std::vector<std::string> splittedLine = splitString(line, '|');
int first = std::stoi(splittedLine[0]);
int second = std::stoi(splittedLine[1]);
rules.emplace_back(first, second);
}
}
return rules;
}
std::vector<Update> parseUpdates(std::vector<std::string>& input) {
std::vector<Update> updates;
for(const auto& line : input) {
if(line.find(',') != std::string::npos) {
std::vector<std::string> splittedString = splitString(line, ',');
std::vector<int> pages;
for(const auto& page : splittedString) {
pages.push_back(std::stoi(page));
}
updates.emplace_back(pages);
}
}
return updates;
}
std::vector<int> topologicalSort(const std::vector<Rule>& rules) {
std::unordered_map<int, std::unordered_set<int>> adjList;
std::unordered_map<int, int> inDegree;
// Step 1: Build the graph
for(const auto& rule : rules) {
adjList[rule.first].insert(rule.second);
inDegree[rule.second]++;
if(inDegree.find(rule.first) == inDegree.end()) {
inDegree[rule.first] = 0;
}
}
// Step 2: Initialize queue with nodes having in degree 0
std::queue<int> zeroInDegreeQueue;
for(const auto& pair : inDegree) {
if(pair.second == 0) {
zeroInDegreeQueue.push(pair.first);
}
}
//Step 3: Process nodes and generate topological order
std::vector<int> topologicalOrder;
while(!zeroInDegreeQueue.empty()) {
int current = zeroInDegreeQueue.front();
zeroInDegreeQueue.pop();
topologicalOrder.push_back(current);
if(adjList.find(current) != adjList.end()) {
for(const auto& neighbor : adjList[current]) {
inDegree[neighbor]--;
if(inDegree[neighbor] == 0) {
zeroInDegreeQueue.push(neighbor);
}
}
}
}
return topologicalOrder;
}
int indexOf(std::vector<int> vec, int element) {
for(int i=0; i< vec.size(); i++) {
if(vec[i] == element) {
return i;
}
}
return -1;
}
//Checks whether a is before b in topological order
bool isBefore(const std::vector<Rule>& rules, int a, int b) {
for(const Rule& rule: rules) {
if(rule.second == a && rule.first == b) {
return false;
}
}
return true;
}
bool isAfter(const std::vector<Rule>& rules, int a, int b) {
for(const Rule& rule : rules) {
if(rule.second == b && rule.first == a) {
return false;
}
}
return true;
}
bool isUpdateCorrect(const Update& update, const std::vector<Rule>& rules) {
std::vector<int> topologicalOrder = topologicalSort(rules);
//Check if all pages are printed after the previous one
for(int i=0; i<update.pages.size(); i++) {
for(int j=0; j<i; j++) {
if(!isBefore(rules, update.pages[j], update.pages[i])) {
return false;
}
}
for(int j=i+1; j<update.pages.size(); j++) {
if(!isAfter(rules, update.pages[j], update.pages[i])) {
return false;
}
}
}
return true;
}
std::vector<Update> determineCorrectUpdates(std::vector<Update>& updates, std::vector<Rule>& rules) {
std::vector<Update> validUpdates;
for(const Update& update : updates) {
if(isUpdateCorrect(update, rules)) {
validUpdates.push_back(update);
}
}
return validUpdates;
}
2024-12-11 18:47:47 +00:00
std::vector<Update> determineIncorrectUpdates(std::vector<Update>& updates, std::vector<Rule>& rules) {
std::vector<Update> validUpdates;
for(const Update& update : updates) {
if(!isUpdateCorrect(update, rules)) {
validUpdates.push_back(update);
}
}
return validUpdates;
}
Update correctUpdate(const Update& update, std::vector<Rule>& rules) {
Update correctedUpdate = update;
for(int i=0; i<correctedUpdate.pages.size(); i++) {
for(int j=0; j<i; j++) {
if(!isBefore(rules, correctedUpdate.pages[j], correctedUpdate.pages[i])) {
std::swap(correctedUpdate.pages[j], correctedUpdate.pages[i]);
}
}
for(int j=i+1; j<correctedUpdate.pages.size(); j++) {
if(!isAfter(rules, correctedUpdate.pages[j], correctedUpdate.pages[i])) {
std::swap(correctedUpdate.pages[j], correctedUpdate.pages[i]);
}
}
}
return correctedUpdate;
}
std::vector<Update> correctUpdates(std::vector<Update>& updates, std::vector<Rule>& rules) {
std::vector<Update> correctedUpdates;
for(const Update& update : updates) {
correctedUpdates.push_back(correctUpdate(update, rules));
}
return correctedUpdates;
}
2024-12-11 18:20:32 +00:00
int calcMiddleSum(std::vector<Update>& updates) {
int sum = 0;
for(const auto& update: updates) {
sum += update.pages[update.pages.size()/2];
}
return sum;
}
int main() {
std::vector<std::string> input = readTextFromFile("../input.txt");
std::vector<Rule> rules = parseRules(input);
std::vector<Update> updates = parseUpdates(input);
2024-12-11 18:47:47 +00:00
std::vector<Update> validUpdates = determineCorrectUpdates(updates, rules);
int result = calcMiddleSum(validUpdates);
2024-12-11 18:20:32 +00:00
std::cout << "The middle sum of the correct Updates is: " << result << std::endl;
2024-12-11 18:47:47 +00:00
std::vector<Update> incorrectUpdates = determineIncorrectUpdates(updates, rules);
std::vector<Update> correctedUpdates = correctUpdates(incorrectUpdates, rules);
int result2 = calcMiddleSum(correctedUpdates);
std::cout << "The middle sum of the corrected Updates is: " << result2 << std::endl;
2024-12-11 18:20:32 +00:00
return 0;
}