zoukankan      html  css  js  c++  java
  • Leetcode Sudoku Solver

    class Solution {
    private:
        int row[9];
        int col[9];
        int blk[9];
        
    public:
        void solveSudoku(vector<vector<char> > &board) {
            if (board.empty() || board[0].empty()) return;
            
            initBits(board);
            
            dfs(board, 0, 0);
        }
        
        bool dfs(vector<vector<char> >& board, int ridx, int cidx) {
            if (ridx == 9) {
                return true; // a valid solution will reach it 
            }
            char ch = board[ridx][cidx];
            bool nr = cidx == 8;
            int blk_id = ridx/3*3 + cidx/3;
            
            if (ch != '.') {
                return dfs(board, ridx + nr, nr ? 0 : (cidx+1));
            }
            
            for (int k=1; k<=9; k++) {
                int msk = 0x1<<(k-1);
                if ((msk|row[ridx]) == row[ridx] 
                        || (msk|col[cidx]) == col[cidx] 
                        || (msk|blk[blk_id]) == blk[blk_id]) {
                    // this means that in a column or row or block (where current (ridx, cidx) fall)
                    // the current number has already been used, so give up this try
                    continue;
                }
                setBits(ridx, cidx, blk_id, msk);
                board[ridx][cidx] = k + '0';
                if (dfs(board, ridx + nr, nr ? 0 : (cidx+1))) return true;
                board[ridx][cidx] = ch;
                unsetBits(ridx, cidx, blk_id, msk);
            }
            return false;
        }
        
        void setBits(int r, int c, int b, int msk) {
            row[r] |= msk;
            col[c] |= msk;
            blk[b] |= msk;
        }
        void unsetBits(int r, int c, int b, int msk) {
            row[r] &= ~msk;
            col[c] &= ~msk;
            blk[b] &= ~msk;
        }
        
        void initBits(vector<vector<char> > &board) {
            memset(row, 0, sizeof(row));
            memset(col, 0, sizeof(col));
            memset(blk, 0, sizeof(blk));
            
            int rm, cm, bm;
            for (int i=0; i<9; i++) {
                int base = i / 3 * 3;
                for (int j=0; j<9; j++) {
                    char ch = board[i][j];
                    if (ch == '.') continue;
                    int msk = 0x1<<(ch - '0' - 1);
                    int blk_idx = base + j / 3;
                    setBits(i, j, blk_idx, msk);
                }
            }
        }
    };

    以前一直没练算法,连dfs也没写过几个,最多就是二叉树的深度优先遍历,哎。。。那就练起吧!

    这题用dfs说白了就是暴力穷举搜索,在每次尝试的时候需要检查填入尝试的数是否会使当前的数独状态遭到破坏,这里用位操作实现检测,每一行,每一列,每一个3*3的block分别给9个位(代码实际上用了int类型),row,col,blk数组,每个元素表示在其代表的范围内数字的出现情况。row[0]、row[1]...分别代表第一行、第二行上数字的出现情况,col[0]、col[1]...分别代表第一列、第二列上的数字出现情况,blk[0]、blk[1]...代表从左向右、从上往下数第一个、第二个3*3block中的数字出现情况。

    mask_digit = 0x1<<(digit-1)    // mask for a digit
    
    area[0] == mask_digit|area[0]    // this digit already used
    
    area[0] |= mask_digit        // use the digit
    
    area[0] &= ~mask_digit     // un-use the digit 

    每个区域(行、列、block)中的数字使用情况的维护如上所示。

    代码中的dfs尝试从上至下一行一行的扫过去,或许可以选择从已有数字最多的行或者列或者block进行,通过一个优先队列,每次都可以在数目较多的区域进行尝试,这样的区域由于已有的数字较多可以尝试的次数就可以大大减少,从而加快搜索速度。

     参考:

    zhuli哥的题解 http://www.cnblogs.com/zhuli19901106/p/3574405.html

  • 相关阅读:
    计算组合数
    UVa11889
    UVa11388
    二分查找
    UVa12096
    UVa156
    UVa400
    京东2017校招编程题
    华为2017秋招测试工程师笔试试卷
    剑指offer第七章&第八章
  • 原文地址:https://www.cnblogs.com/lailailai/p/3598818.html
Copyright © 2011-2022 走看看