classSudoGenerateAlgorithm { public: // To get the sudoku, you should generate the template first. staticvoidcalTemplate(int count = MAX_TEMPLATE_COUNT); // Search valid diffrent initial sudoku passed to solve algorithm staticvoiddfs(SudoMatrix& crtMatrix, int pos, int cnt1, int cnt2, int cnt3);
// The permutation indicates the first row of the generated sudoku. static SudoMatrix getSudokuFromPermutation(std::vector<int>& permutation, int templateId);
// Generate matrices of specific count and stored in pre-allocated array. // The max count is 2e6 if the first number is fixed. // Otherwise the max count is 1.8e7. // Return the actual count of generated matrices. intgenerateFinalState(int count, Sudo::SudoMatrix* matrixArr, int fixFirstNumber = 0)const; };
boolSudoSolveAlgorithm::solve(SudoMatrix& mat) { // Fill the matrix with known message if (!fillState(mat)) { returnfalse; } // Use dfs to find the solution if (!dfs()) { returnfalse; } // Get result mat = _sudoState.getMat(); returntrue; }
// For each entry and number, initialize their state for (int i = 0; i < SudoMatrix::SUDO_SIDELENGTH; i++) { for (int j = 0; j < SudoMatrix::SUDO_SIDELENGTH; j++) { _entryChoises[i][j].init(SudoChoice::Type::ENTRY, i, j); _numberChoises[i][j].init(SudoChoice::Type::NUMBER, i, j); if (mat(i, j) == 0) { _entryChoises[i][j].setAllOne(); } _numberChoises[i][j].setAllOne(); } }
// For each known number, update the message through setNumber() for (int i = 0; i < SudoMatrix::SUDO_SIDELENGTH; i++) { for (int j = 0; j < SudoMatrix::SUDO_SIDELENGTH; j++) { if (mat(i, j) != 0) { if (!setNumber(i, j, mat(i, j), false)) { returnfalse; } } } } returntrue; }
boolSudoSolveAlgorithm::dfs() { if (_sudoState.getStep() >= SudoMatrix::SUDO_ELEMENTS_CNT) { returntrue; }
constauto& op = _sudoState.getMinForkOperation();
if (op.getType() == SudoChoice::ENTRY) { // ENRTY constauto& set = op.getChoices(); for (auto num : set) { bool yes = false; if (_sudoState.setNumber(op.getPosIOrNumber(), op.getPosJOrPalace(), num + 1)) { if (dfs()) yes = true; } if (!yes) _sudoState.recall(); else returntrue; } } else { // NUMBER .......// do the same thing }
boolSudoState::setNumber(int i, int j, int num, bool recordLog) { assert(_mat(i, j) == 0); // the entry must be empty assert(num >= 1 && num <= 9); // number must in 1~9
int palaceId = SudoMatrix::getPalaceId(i, j); int idInPalace = SudoMatrix::getIdInPalace(i, j);
bool valid = true; _mat(i, j) = num;
// record currentLog .....
// Ban all the choices in (i, j) ......
// Update the choices of entries with same column ......
// Update the choices of entries with same row ......
// Update the choices of entries with same palace ......
假设当前某个数字是$x$,有$d$位,在它的前后放了一个$y$,那么这步操作的结果是$x \leftarrow y * 10^{d+2} + x \times10 + y$。可以发现,后面的乘法和加法都十分好维护。用两个lazy变量来标记区间该乘和该加的值。每次乘的时候还要改变加的标记。问题的关键是,前面加的那一堆东西和当前数无关,而是和当前数的位数有关。