diff --git a/2022/city/10/domino/main.cpp b/2022/city/10/domino/main.cpp new file mode 100644 index 0000000..14c3794 --- /dev/null +++ b/2022/city/10/domino/main.cpp @@ -0,0 +1,209 @@ +#include + +using namespace std; + +// ifstream in("test.in"); +// ofstream out("test.out"); + + + +struct Domino { + int side1; + int side2; +}; + + +// Global variables +int n; +int max_length = 1; +Domino* dominos[28]; +vector dominos_by_side[7]; +unordered_set ignored_dominos; + + +bool evaluate(unordered_set& ignore_candidates) { + ignore_candidates.clear(); + + // Filled during the loop, used later + unordered_set used_dominos; + + // Find degree of each pip + int odd_vertices_count = 0; + for (int i = 0; i < 7; i++) { + int dominos_count = 0; + for (auto it = dominos_by_side[i].begin(); it != dominos_by_side[i].end(); it++) { + if (ignored_dominos.count(*it) != 1) { + dominos_count++; + used_dominos.insert(*it); + } + } + + // Mark as ignored candidate all dominos with pips that have odd degree + if (dominos_count % 2 == 1) { + odd_vertices_count++; + ignore_candidates.insert(dominos_by_side[i].begin(), dominos_by_side[i].end()); + } + } + // cout << odd_vertices_count << " odd vertices found" << endl; + + // Condition 1 + if (odd_vertices_count > 2) { + return false; + } + + // Now evaluate using DFS here + // cout << "Evaluating with DFS" << endl; + unordered_set visited_dominos; + visited_dominos.clear(); + deque domino_queue; + domino_queue.push_back(*used_dominos.begin()); + visited_dominos.insert(*used_dominos.begin()); + bool visited_pips[7]; + for (int i = 0; i < 7; i++) { + visited_pips[i] = 0; + } + + while (domino_queue.size() > 0) { + Domino* domino = domino_queue.front(); + domino_queue.pop_front(); + + if (!visited_pips[domino->side1]) { + for (auto it = dominos_by_side[domino->side1].begin(); it != dominos_by_side[domino->side1].end(); it++) { + if (ignored_dominos.count(*it) == 1) { + continue; + } + if (visited_dominos.count(*it) == 0) { + visited_dominos.insert(*it); + domino_queue.push_back(*it); + } + } + visited_pips[domino->side1] = 1; + } + + if (!visited_pips[domino->side2]) { + for (auto it = dominos_by_side[domino->side2].begin(); it != dominos_by_side[domino->side2].end(); it++) { + if (ignored_dominos.count(*it) == 1) { + continue; + } + if (visited_dominos.count(*it) == 0) { + visited_dominos.insert(*it); + domino_queue.push_back(*it); + } + } + visited_pips[domino->side2] = 1; + } + } + + if (visited_dominos.size() != used_dominos.size()) { + cout << "DFS invalid " << visited_dominos.size() << "/" << used_dominos.size() << " visited" << endl; + // ignore_candidates.insert(used_dominos.begin(), used_dominos.end()); + if (visited_dominos.size() > (used_dominos.size() / 2)) { + for (auto it = used_dominos.begin(); it != used_dominos.end(); it++) { + if (visited_dominos.count(*it) == 0) { + ignore_candidates.insert(*it); + } + } + } else { + ignore_candidates.insert(used_dominos.begin(), used_dominos.end()); + } + return false; + } + // cout << "DFS VALID" << endl; + return true; +} + + +bool evaluate() { + unordered_set empty_set; + return evaluate(empty_set); +} + + + + +void solve() { + // cout << ignored_dominos.size() << " ignored dominos deep" << endl; + + unordered_set ignore_candidates; // populated in evaluate() + if (evaluate(ignore_candidates)) { + cout << "Found new max length " << max_length << endl; + max_length = max(max_length, (int)(n - ignored_dominos.size())); + return; + } + + // Evaluate if it's worth going deeper based on previous findings + if (max_length > (n - ignored_dominos.size() - 1)) { + return; + } + + // for (int i = 0; i < dominos_to_ignore.size(); i++) { + for (auto it = ignore_candidates.begin(); it != ignore_candidates.end(); it++) { + #define target_domino (*it) + if (ignored_dominos.count(target_domino)) { + continue; + } + ignored_dominos.insert(target_domino); + + solve(); + + ignored_dominos.erase(target_domino); + } +} + + + +// pips = vertices; dominos = edges +// Solve Euler path +int main(int argc, char *argv[]) { + string inName = "test.in"; + string outName = "test.out"; + + if (argc > 1) { + inName = argv[1]; + cout << "Using \"" << inName << "\" for test name" << endl; + } else { + cout << "Warning: no in name provided, defaulting to test.in" << endl; + } + + if (argc > 2) { + outName = argv[2]; + cout << "Using \"" << outName << "\" for out name" << endl; + } else { + cout << "Warning: no out name proviced, defaulting to test.out" << endl; + } + + ifstream in(inName); + ofstream out(outName); + + in >> n; + + // cout << "n: " << n << endl; + + if (n < 2) { + out << "1"; + in.close(); + out.close(); + return 0; + } + + for (int i = 0; i < n; i++) { + Domino* domino = new Domino(); + in >> (*domino).side1; + in >> (*domino).side2; + + dominos[i] = domino; + + dominos_by_side[(domino -> side1)].push_back(domino); + dominos_by_side[(domino -> side2)].push_back(domino); + } + + ignored_dominos.clear(); + + solve(); + // ignored_dominos.insert(dominos[0]); + // cout << dominos[0]->side1 << " " << dominos[0]->side2 << endl; + cout << "Result: " << max_length << endl; + + out << max_length << endl; + return 0; +} diff --git a/2022/city/10/domino/main_slow.cpp b/2022/city/10/domino/main_slow.cpp new file mode 100644 index 0000000..574e972 --- /dev/null +++ b/2022/city/10/domino/main_slow.cpp @@ -0,0 +1,143 @@ +#include + +using namespace std; + +// ifstream in("test.in"); +// ofstream out("test.out"); + + +struct Domino { + int side1; + int side2; +}; + + +// Global variables +int n; +int max_length = 1; +unordered_set used_dominos; +vector dominos_by_side[7]; + + +// Recursive solution +void buildTrain(int next_side, int current_length) { + // cout << "Building train; Current length: " << current_length << "; next side: " << next_side << endl; + if (current_length > max_length) { + max_length = current_length; + + // Debug print + // cout << "updated to " << current_length << endl; + // if (max_length == 8) { + // cout << "found 8" << endl; + // for (auto it = used_dominos.begin(); it != used_dominos.end(); it++) { + // cout << (*it)->side1 << " " << (*it)->side2 << endl; + // } + // } + } + + int stop = dominos_by_side[next_side].size(); + + for (int i = 0; i < stop; i++) { + // Looking at Domino dominos_by_side[next_side][i] + #define matched_domino dominos_by_side[next_side][i] + // Skip if already part of the train + if (used_dominos.count(matched_domino) > 0) { + continue; + } + + + // The logic for elongating the train + used_dominos.insert(matched_domino); + + // Figure out if the domino matched by side1 or side2: + int other_side; + if ((matched_domino->side1) == next_side) { + other_side = matched_domino->side2; + } else { + other_side = matched_domino->side1; + } + + // The recursion + buildTrain(other_side, current_length + 1); + + + // Deconstruct + used_dominos.erase(matched_domino); + } +} + + +int main(int argc, char *argv[]) { + + string inName = "test.in"; + string outName = "test.out"; + + if (argc > 1) { + inName = argv[1]; + cout << "Using \"" << inName << "\" for test name" << endl; + } else { + cout << "Warning: no in name provided, defaulting to test.in" << endl; + } + + if (argc > 2) { + outName = argv[2]; + cout << "Using \"" << outName << "\" for out name" << endl; + } else { + cout << "Warning: no out name proviced, defaulting to test.out" << endl; + } + + ifstream in(inName); + ofstream out(outName); + + in >> n; + + // cout << "n: " << n << endl; + + if (n < 2) { + out << "1"; + in.close(); + out.close(); + return 0; + } + + + Domino* dominos[n]; + for (int i = 0; i < n; i++) { + Domino* domino = new Domino(); + in >> (*domino).side1; + in >> (*domino).side2; + + dominos[i] = domino; + + dominos_by_side[(domino -> side1)].push_back(domino); + dominos_by_side[(domino -> side2)].push_back(domino); + } + + // Debug print + for (int j = 0; j < n; j++) { + cout << dominos[j] << endl; + cout << (dominos[j]->side1) << " " << (dominos[j]->side2) << endl; + } + + used_dominos.clear(); + // for (int i = 0; i < n; i++) { + // #define start_domino dominos[i] + + // // cout << "starting with domino " << start_domino->side1 << " " << start_domino->side2 << "" << start_domino << endl; + // used_dominos.insert(start_domino); + + // buildTrain(start_domino->side1, 1); + // buildTrain(start_domino->side2, 1); + + // used_dominos.clear(); + // } + + used_dominos.insert(dominos[2]); + cout << "start " << dominos[2]->side1 << " " << dominos[2]->side2 << endl; + buildTrain(dominos[2]->side1, 1); + + + cout << "Result: " << max_length << endl; + + return 0; +}