Sudoku Solver

Sudoku Solver 题解


题目描述

Sudoku Solver
即求解数独游戏。

数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。1

如:上图中则有一个例子。

题解

这题出现在算法类题目里我还是很惊讶的,不过看到了,就顺手做了下。
利用唯一余数法,即用格位去找唯一可填数字,格位唯一可填数字称为唯余解(Naked Single)。若找不到唯余解,则随意选择一个数字进行深度搜索,并记录当前状态以便回溯。时间复杂度很高,应该是O(b^d)b为可选解,d为盘面的空位数。但由于存在唯余解,大多数情况下b = 1,所以很快就能得到结果。

代码

#define n 9
#define POS2(i, j) ((i) * n + (j))
#define POS3(i, j) ((i) * nsquare + (j))
#define POS(i, j, k) (POS3(i, POS2(j, k)))
#define COMPOSE(i, j) (((i) << 16) | (j))
#define VAIN ('.') // 46

char* used; 

class Solution {
public:
    bool operator()(int a, int b) const {
        int va = used[POS2(a >> 16, a & 0xFFFF)], vb = used[POS2(b >> 16, b & 0xFFFF)];
        return va > vb || (va == vb && a < b);
    }
    void solveSudoku(vector<vector<char>>& board) {
        if (board.empty() || board.size() != board[0].size())
            return;
        // n = board.size();
        int nsqrt = sqrt(n), nsquare = n * n, nm = nsquare * (n + 1) * sizeof(char);
        used = (char*)malloc(nm);
        memset(used, 0, nm);
        for (int i = n; i--; ) {
            vector<char>& vi = board[i];
            for (int j = n; j--; ) {
                if (vi[j] != VAIN) {
                    int ct = vi[j] - '0';
                    int row = i / nsqrt * nsqrt, col = j / nsqrt * nsqrt;
                    for (int k = row + nsqrt; --k >= row; )
                        for (int kk = col + nsqrt; --kk >= col; ) {
                            int t2 = POS2(k, kk), t3 = POS3(ct, t2);
                            if (used[t3])
                                continue;
                            used[t3] = 1;
                            ++used[t2];
                        }
                    for (int k = 0; k < row; ++k) {
                        int t2 = POS2(k, j), t3 = POS3(ct, t2);
                        if (used[t3])
                            continue;
                        used[t3] = 1;
                        ++used[t2];
                    }
                    for (int k = row + nsqrt; k < n; ++k) {
                        int t2 = POS2(k, j), t3 = POS3(ct, t2);
                        if (used[t3])
                            continue;
                        used[t3] = 1;
                        ++used[t2];
                    }
                    for (int k = 0; k < col; ++k) {
                        int t2 = POS2(i, k), t3 = POS3(ct, t2);
                        if (used[t3])
                            continue;
                        used[t3] = 1;
                        ++used[t2];
                    }
                    for (int k = col + nsqrt; k < n; ++k) {
                        int t2 = POS2(i, k), t3 = POS3(ct, t2);
                        if (used[t3])
                            continue;
                        used[t3] = 1;
                        ++used[t2];
                    }
                }
            }
        }
        
        std::set<int, Solution> next;
        for (int i = n; i--; ) {
            vector<char>& vi = board[i];
            for (int j = n; j--; )
                if (vi[j] == VAIN)
                    next.insert(COMPOSE(i, j));
                else
                    used[POS2(i, j)] = 9;
        }
        std::vector<std::pair<int, char*>> stack;
        NextLoop:
        for (std::set<int, Solution>::iterator it = next.begin(); it != next.end(); it = next.begin()) {
            int ct = 0, i = *it >> 16, j = *it & 0xFFFF, t2 = POS2(i, j);
            if (used[t2] > 8) {
                GoBack:
                free(used);
                used = stack.back().second;
                ct = stack.back().first;
                stack.pop_back();
                next.clear();
                for (int i = n; i--; )
                    for (int j = n; j--; )
                        if (used[POS2(i, j)] != 9) {
                            next.insert(COMPOSE(i, j));
                            board[i][j] = VAIN;
                        }
                it = next.begin();
                i = *it >> 16; j = *it & 0xFFFF; t2 = POS2(i, j);
            }
            while (++ct <= n)
                if (!used[POS3(ct, t2)]) {
                    if (used[t2] < 8) {
                        char* tmp = (char*)malloc(nm);
                        memcpy(tmp, used, nm);
                        stack.push_back(std::pair<int, char*>(ct, tmp));
                    }
                    board[i][j] = ct + '0';
                    used[t2] = 9;
                    next.erase(it);
                    int row = i / nsqrt * nsqrt, col = j / nsqrt * nsqrt;
                    for (int k = row + nsqrt; --k >= row; )
                        for (int kk = col + nsqrt; --kk >= col; ) {
                            int t2 = POS2(k, kk), t3 = POS3(ct, t2);
                            if (used[t2] == 9 || used[t3])
                                continue;
                            next.erase(COMPOSE(k, kk));
                            used[t3] = 1;
                            ++used[t2];
                            next.insert(COMPOSE(k, kk));
                        }
                    for (int k = 0; k < row; ++k) {
                        int t2 = POS2(k, j), t3 = POS3(ct, t2);
                        if (used[t2] == 9 || used[t3])
                            continue;
                        next.erase(COMPOSE(k, j));
                        used[t3] = 1;
                        ++used[t2];
                        next.insert(COMPOSE(k, j));
                    }
                    for (int k = row + nsqrt; k < n; ++k) {
                        int t2 = POS2(k, j), t3 = POS3(ct, t2);
                        if (used[t2] == 9 || used[t3])
                            continue;
                        next.erase(COMPOSE(k, j));
                        used[t3] = 1;
                        ++used[t2];
                        next.insert(COMPOSE(k, j));
                    }
                    for (int k = 0; k < col; ++k) {
                        int t2 = POS2(i, k), t3 = POS3(ct, t2);
                        if (used[t2] == 9 || used[t3])
                            continue;
                        next.erase(COMPOSE(i, k));
                        used[t3] = 1;
                        ++used[t2];
                        next.insert(COMPOSE(i, k));
                    }
                    for (int k = col + nsqrt; k < n; ++k) {
                        int t2 = POS2(i, k), t3 = POS3(ct, t2);
                        if (used[t2] == 9 || used[t3])
                            continue;
                        next.erase(COMPOSE(i, k));
                        used[t3] = 1;
                        ++used[t2];
                        next.insert(COMPOSE(i, k));
                    }
                    goto NextLoop;
                }
            goto GoBack;
        }
        for (free(used); stack.size(); stack.pop_back())
            free(stack.back().second);
    }

};

总结

主要应用了深度搜索思想。


  1. 百度百科 数独
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值