Sudoku Solver

Sudoku Solver 題解


題目描述

Sudoku Solver
即求解數獨遊戲。算法

數獨盤面是個九宮,每一宮又分爲九個小格。在這八十一格中給出必定的已知數字和解題條件,利用邏輯和推理,在其餘的空格上填入1-9的數字。使1-9每一個數字在每一行、每一列和每一宮中都只出現一次,因此又稱「九宮格」。1oop

如:上圖中則有一個例子。spa

題解

這題出如今算法類題目裏我仍是很驚訝的,不過看到了,就順手作了下。
利用惟一餘數法,即用格位去找惟一可填數字,格位惟一可填數字稱爲惟餘解(Naked Single)。若找不到惟餘解,則隨意選擇一個數字進行深度搜索,並記錄當前狀態以便回溯。時間複雜度很高,應該是O(b^d)b爲可選解,d爲盤面的空位數。但因爲存在惟餘解,大多數狀況下b = 1,因此很快就能獲得結果。code

代碼

#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. 百度百科 數獨
相關文章
相關標籤/搜索