YauhenMardan

Untitled

May 31st, 2019
135
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.36 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <memory>
  5. using namespace std;
  6.  
  7. const string LETTERS="ABCDEFGHIJKLMNOP";
  8. const int L_SZ=16;
  9. const int S_SZ=4;
  10.  
  11. class Possible {
  12. vector<bool> _b;
  13. public:
  14. Possible() : _b(L_SZ, true) {}
  15. bool is_on(int i) const { return _b[i-1]; }
  16. int count() const { return std::count(_b.begin(), _b.end(), true); }
  17. void eliminate(int i) { _b[i-1] = false; }
  18. int val() const {
  19. auto it = find(_b.begin(), _b.end(), true);
  20. return (it != _b.end() ? 1 + (it - _b.begin()) : -1);
  21. }
  22. string str(int wth) const;
  23. };
  24.  
  25. string Possible::str(int width) const {
  26. string s(width, ' ');
  27. int k = 0;
  28. for (int i = 1; i <= L_SZ; i++) {
  29. if (is_on(i)) s[k++] = 'A' + i;
  30. }
  31. return s;
  32. }
  33.  
  34. class Sudoku {
  35. vector<Possible> _cells;
  36. static vector< vector<int> > _group, _neighbors, _groups_of;
  37.  
  38. bool eliminate(int k, int val);
  39. public:
  40. Sudoku(string s);
  41. static void init();
  42.  
  43. Possible possible(int k) const { return _cells[k]; }
  44. bool is_solved() const;
  45. bool assign(int k, int val);
  46. int least_count() const;
  47. void write(ostream& o) const;
  48. };
  49.  
  50. bool Sudoku::is_solved() const {
  51. for (int k = 0; k < _cells.size(); k++) {
  52. if (_cells[k].count() != 1) {
  53. return false;
  54. }
  55. }
  56. return true;
  57. }
  58.  
  59. void Sudoku::write(ostream& o) const {
  60. int width = 1;
  61. for (int k = 0; k < _cells.size(); k++) {
  62. width = max(width, 1 + _cells[k].count());
  63. }
  64. const string sep(S_SZ * width, '-');
  65. for (int i = 0; i < L_SZ; i++) {
  66. if (i == 4 || i == 8 || i == 12) {
  67. o << sep << "+-" << sep << "+" << sep << endl;
  68. }
  69. for (int j = 0; j < L_SZ; j++) {
  70. if (i == 4 || i == 8 || i == 12) o << "| ";
  71. o << _cells[i*L_SZ + j].str(width);
  72. }
  73. o << endl;
  74. }
  75. }
  76.  
  77. vector< vector<int> >
  78. Sudoku::_group(S_SZ*L_SZ), Sudoku::_neighbors(L_SZ*L_SZ), Sudoku::_groups_of(L_SZ*L_SZ);
  79.  
  80. void Sudoku::init() {
  81. for (int i = 0; i < L_SZ; i++) {
  82. for (int j = 0; j < L_SZ; j++) {
  83. const int k = i*L_SZ + j;
  84. // const int x[3] = {i, 9 + j, 18 + (i/3)*3 + j/3,};
  85. const int x[4] = {i, L_SZ + j, L_SZ*2 + (i/S_SZ)*S_SZ + j/S_SZ,L_SZ*3 + (i/(2*S_SZ))*(2*S_SZ) + j/(2*S_SZ)};
  86. for (int g = 0; g < 4; g++) {
  87. _group[x[g]].push_back(k);
  88. _groups_of[k].push_back(x[g]);
  89. }
  90. }
  91. }
  92. for (int k = 0; k < _neighbors.size(); k++) {
  93. for (int x = 0; x < _groups_of[k].size(); x++) {
  94. for (int j = 0; j < L_SZ; j++) {
  95. int k2 = _group[_groups_of[k][x]][j];
  96. if (k2 != k) _neighbors[k].push_back(k2);
  97. }
  98. }
  99. }
  100. }
  101.  
  102. bool Sudoku::assign(int k, int val) {
  103. for (int i = 1; i <= L_SZ; i++) {
  104. if (i != val) {
  105. if (!eliminate(k, i)) return false;
  106. }
  107. }
  108. return true;
  109. }
  110.  
  111. bool Sudoku::eliminate(int k, int val) {
  112. if (!_cells[k].is_on(val)) {
  113. return true;
  114. }
  115. _cells[k].eliminate(val);
  116. const int N = _cells[k].count();
  117. if (N == 0) {
  118. return false;
  119. } else if (N == 1) {
  120. const int v = _cells[k].val();
  121. for (int i = 0; i < _neighbors[k].size(); i++) {
  122. if (!eliminate(_neighbors[k][i], v)) return false;
  123. }
  124. }
  125. for (int i = 0; i < _groups_of[k].size(); i++) {
  126. const int x = _groups_of[k][i];
  127. int n = 0, ks;
  128. for (int j = 0; j < L_SZ; j++) {
  129. const int p = _group[x][j];
  130. if (_cells[p].is_on(val)) {
  131. n++, ks = p;
  132. }
  133. }
  134. if (n == 0) {
  135. return false;
  136. } else if (n == 1) {
  137. if (!assign(ks, val)) {
  138. return false;
  139. }
  140. }
  141. }
  142. return true;
  143. }
  144.  
  145. int Sudoku::least_count() const {
  146. int k = -1, min;
  147. for (int i = 0; i < _cells.size(); i++) {
  148. const int m = _cells[i].count();
  149. if (m > 1 && (k == -1 || m < min)) {
  150. min = m, k = i;
  151. }
  152. }
  153. return k;
  154. }
  155.  
  156. Sudoku::Sudoku(string s)
  157. : _cells(L_SZ*L_SZ)
  158. {
  159. int k = 0;
  160. for (int i = 0; i < s.size(); i++) {
  161. if (s[i] >= 'A' && s[i] <= 'A') {
  162. if (!assign(k, s[i] - 'A')) {
  163. cerr << "error" << endl;
  164. return;
  165. }
  166. k++;
  167. } else if (s[i] == '-' || s[i] == '.') {
  168. k++;
  169. }
  170. }
  171. }
  172.  
  173. unique_ptr<Sudoku> solve(unique_ptr<Sudoku> S) {
  174. if (S == nullptr || S->is_solved()) {
  175. return S;
  176. }
  177. int k = S->least_count();
  178. Possible p = S->possible(k);
  179. for (int i = 1; i <= L_SZ; i++) {
  180. if (p.is_on(i)) {
  181. unique_ptr<Sudoku> S1(new Sudoku(*S));
  182. if (S1->assign(k, i)) {
  183. if (auto S2 = solve(std::move(S1))) {
  184. return S2;
  185. }
  186. }
  187. }
  188. }
  189. return {};
  190. }
  191.  
  192. int main() {
  193. Sudoku::init();
  194. string line;
  195. while (getline(cin, line)) {
  196. if (auto S = solve(unique_ptr<Sudoku>(new Sudoku(line)))) {
  197. S->write(cout);
  198. } else {
  199. cout << "No solution";
  200. }
  201. cout << endl;
  202. }
  203. }
Advertisement
Add Comment
Please, Sign In to add comment