• 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

  • 相关阅读:
    Oracle存储过程获取YYYY-MM-DD的时间格式
    EXP/IMP 导出生产库表的指定数据到测试库一例
    java sm4国密算法加密、解密
    oracle 三表关联查询
    oracle 两表关联查询
    oracle 批量更新之将一个表的数据批量更新至另一个表
    js 不固定传参
    CocoaPods为project的全部target添加依赖支持
    QML 开发神奇加成之为网络资源设置本地缓存
    一步步走向国际乱码大赛-- 恶搞C语言
  • 原文地址:https://www.cnblogs.com/lailailai/p/3598818.html
Copyright © 2020-2023  润新知