Euler_96.cpp (6527B)
1 #include <array> 2 #include <fstream> 3 #include <sstream> 4 #include <unordered_set> 5 6 #include "Euler.h" 7 8 typedef std::array<std::array<int, 9>, 9> sudoku; 9 typedef std::unordered_set<int> set; 10 11 bool check(sudoku& bifurcation) { 12 for (int i = 0; i < 9; ++i) { 13 set h, v; 14 15 for (int j = 0; j < 9; ++j) { 16 h.insert(bifurcation[i][j]); 17 v.insert(bifurcation[j][i]); 18 } 19 20 if (h.size() < 9 || v.size() < 9) { 21 return false; 22 } 23 } 24 25 for (int l = 0; l < 3; ++l) { 26 for (int k = 0; k < 3; ++k) { 27 set subgroup; 28 29 for (int i = l * 3; i < (l * 3) + 3; ++i) { 30 for (int j = k * 3; j < (k * 3) + 3; ++j) { 31 subgroup.insert(bifurcation[i][j]); 32 } 33 } 34 35 if (subgroup.size() < 9) { 36 return false; 37 } 38 } 39 } 40 41 return true; 42 } 43 44 void reset_hv(sudoku& puzzle, std::array<set, 9>& h, std::array<set, 9>& v) { 45 for (int i = 0; i < 9; ++i) { 46 h[i].clear(); v[i].clear(); 47 48 for (int j = 0; j < 9; ++j) { 49 h[i].insert(puzzle[i][j]); 50 v[i].insert(puzzle[j][i]); 51 } 52 } 53 } 54 55 void reset_subgroup(sudoku& puzzle, set& subgroup, set& missing, int l, int k) { 56 subgroup.clear(); missing.clear(); 57 58 for (int i = l * 3; i < (l * 3) + 3; ++i) { 59 for (int j = k * 3; j < (k * 3) + 3; ++j) { 60 subgroup.insert(puzzle[i][j]); 61 } 62 } 63 64 for (int i = 1; i <= 9; ++i) { 65 if (subgroup.find(i) == subgroup.end()) { 66 missing.insert(i); 67 } 68 } 69 } 70 71 void found(sudoku& puzzle, int x, int i, int j, int k, int l, bool& r, std::array<set, 9>& h, std::array<set, 9>& v, set& s, set& m) { 72 puzzle[i][j] = x; 73 r = true; 74 75 reset_hv(puzzle, h, v); 76 reset_subgroup(puzzle, s, m, l, k); 77 } 78 79 sudoku reduce(sudoku& puzzle) { 80 bool reduced; 81 do { 82 reduced = false; 83 84 std::array<set, 9> h, v; 85 86 reset_hv(puzzle, h, v); 87 88 for (int l = 0; l < 3; ++l) { 89 for (int k = 0; k < 3; ++k) { 90 set missing, subgroup; 91 reset_subgroup(puzzle, subgroup, missing, l, k); 92 93 for (int i = l * 3; i < (l * 3) + 3; ++i) { 94 for (int j = k * 3; j < (k * 3) + 3; ++j) { 95 if (puzzle[i][j] <= 0) { 96 if (missing.size() == 1) { 97 found(puzzle, *missing.begin(), i, j, k, l, reduced, h, v, subgroup, missing); 98 continue; 99 } 100 101 set matches; 102 103 for (int x : missing) { 104 if (h[i].find(x) == h[i].end() && v[j].find(x) == v[j].end()) { 105 matches.insert(x); 106 } 107 108 if (subgroup.find(x) == subgroup.end()) { 109 int li1 = (l * 3) + ((i + 1) % 3), li2 = (l * 3) + ((i + 2) % 3), 110 kj1 = (k * 3) + ((j + 1) % 3), kj2 = (k * 3) + ((j + 2) % 3); 111 112 if (((h[li1].find(x) != h[li1].end()) && (h[li2].find(x) != h[li2].end()) 113 && ((puzzle[i][kj1] > 0) || v[kj1].find(x) != v[kj1].end()) 114 && ((puzzle[i][kj2] > 0) || v[kj2].find(x) != v[kj2].end())) || ( 115 (v[kj1].find(x) != v[kj1].end()) && (v[kj2].find(x) != v[kj2].end()) 116 && ((puzzle[li1][j] > 0) || h[li1].find(x) != h[li1].end()) 117 && ((puzzle[li2][j] > 0) || h[li2].find(x) != h[li2].end()))) { 118 found(puzzle, x, i, j, k, l, reduced, h, v, subgroup, missing); 119 break; 120 } 121 } 122 } 123 124 if (matches.size() == 1) { 125 found(puzzle, *matches.begin(), i, j, k, l, reduced, h, v, subgroup, missing); 126 continue; 127 } 128 } 129 } 130 } 131 } 132 } 133 } while (reduced); 134 135 return puzzle; 136 } 137 138 //need to modify bifurcation to start with lowest branching factor rather than sequentially. 139 sudoku bifurcate(sudoku bifurcation) { 140 if (!check(bifurcation)) { 141 return {}; 142 } 143 144 for (int i = 0; i < 9; ++i) { 145 for (int j = 0; j < 9; ++j) { 146 if (bifurcation[i][j] <= 0) { 147 for (int k = 1; k <= 9; ++k) { 148 bifurcation[i][j] = k; 149 150 sudoku candidate = bifurcate(bifurcation); 151 152 if (check(candidate)) { 153 return candidate; 154 } 155 } 156 } 157 } 158 } 159 160 return bifurcation; 161 } 162 163 void print(sudoku puzzle) { 164 for (int i = 0; i < 9; ++i) { 165 if (i % 3 == 0) { 166 std::cout << "-------------------" << std::endl; 167 } 168 for (int j = 0; j < 9; ++j) { 169 std::cout << ((j % 3 == 0) ? "|" : " ") << ((puzzle[i][j] < 0) ? 0 : puzzle[i][j]); 170 } 171 std::cout << "|" << std::endl; 172 } 173 std::cout << "-------------------" << std::endl << std::endl; 174 } 175 176 int Euler::Sudoku() 177 { 178 std::array<sudoku, 50> sudokus; 179 std::ifstream file; 180 std::string temp; 181 int i = -1, j = 0, empty = 0, sum = 0; 182 183 file.open("files/p096_sudoku.txt"); 184 185 while(std::getline(file, temp)) { 186 if (temp[0] == 'G') { 187 i++; j = 0; empty = 0; continue; 188 } 189 190 for (int k = 0; k < 9; ++k) { 191 sudokus[i][j][k] = ((temp[k] - 48) != 0) ? temp[k] - 48 : empty--; 192 } 193 194 j++; 195 } 196 197 file.close(); 198 199 for (int j = 0; j < 5; ++j) { 200 sudoku puzzle = sudokus[j]; 201 std::cout << "next puzzle " << j << ":" << std::endl; 202 print(puzzle); 203 sudoku reduced = reduce(puzzle); 204 std::cout << "reduced:" << std::endl; 205 print(reduced); 206 sudoku solution = bifurcate(reduced); 207 std::cout << "solution:" << std::endl; 208 print(solution); 209 std::stringstream ss; 210 ss << solution[0][0] << solution[0][1] << solution[0][2]; 211 int temp; 212 ss >> temp; 213 sum += temp; 214 215 } 216 217 return sum; 218 }