數獨求解

數獨是一個很經典的問題,由於數獨的規模很小,暴力破解數獨也是一個很不錯的方法!我就是採用暴力破解的辦法去尋找數獨的解,在求解的過程中按照人類的思維大大減少了搜索路徑的數量!

我設置了一個標記,flag用於標記某一行、某一列以及某一塊是否已經有了某個數,見代碼31-33行,每次向空格里填一個數,然後添加標記,接下來的搜索中在衝突區域就不會再使用這個數了。這種方法避免了每次填完所有空再檢驗!

#include <iostream>

int get_flag(int x, int flag)
{
    return flag & (1 << (x - 1));
}

int set_flag(int x, int flag)
{
    return flag | (1 << (x - 1));
}

int reset_flag(int x, int flag)
{
    return flag & (~(1 << (x - 1)));
}

bool solve_sudoku(int x, int y, int flag[3][9], int map[9][9])
{
    if (x == 9)
        return true;

    if (map[x][y] != 0)
        return solve_sudoku(x+(y+1)/9, (y+1)%9, flag, map);

    for (int i = 1; i <= 9; i++) {
        int b = get_flag(i, flag[0][x]);
        b |= get_flag(i, flag[1][y]);
        b |= get_flag(i, flag[2][x/3*3+y/3]);
        if (!b) {
            flag[0][x] = set_flag(i, flag[0][x]);
            flag[1][y] = set_flag(i, flag[1][y]);
            flag[2][x/3*3+y/3] = set_flag(i, flag[2][x/3*3+y/3]);
            if (solve_sudoku(x+(y+1)/9, (y+1)%9, flag, map)) {
                map[x][y] = i;
                return true;
            }
            flag[0][x] = reset_flag(i, flag[0][x]);
            flag[1][y] = reset_flag(i, flag[1][y]);
            flag[2][x/3*3+y/3] = reset_flag(i, flag[2][x/3*3+y/3]);
        }
    }

    return false;
}

void sudoku(int map[9][9])
{
    int flag[3][9];
    for (int i = 0; i < 9; i++)
        flag[0][i] = flag[1][i] = flag[2][i] = 0;
    for (int i = 0; i < 9; i++)
        for (int j = 0; j < 9; j++)
            if (map[i][j]) {
                flag[0][i] = set_flag(map[i][j], flag[0][i]);
                flag[1][j] = set_flag(map[i][j], flag[1][j]);
                flag[2][i/3*3+j/3] = set_flag(map[i][j], flag[2][i/3*3+j/3]);
             }
    solve_sudoku(0, 0, flag, map);
}

void print(int map[9][9])
{
    std::cout << "┏";
    for (int i = 0; i < 8; i++)
        if (i == 2 || i == 5)
            std::cout << "━━━┳";
        else
            std::cout << "━━━━";
    std::cout << "━━━┓" << std::endl;
    for (int i = 0; i < 9; i++) {
        std::cout << "┃";
        for (int j = 0; j < 9; j++) {
            std::cout << " " << map[i][j] << " ";
            if (j % 3 == 2)
                std::cout << "┃";
            else
                std::cout << " ";
        }
        std::cout << std::endl;
        if (i == 2 || i == 5) {
            std::cout << "┣";
            for (int j = 0; j < 8; j++)
                if (j == 2 || j == 5)
                    std::cout << "━━━╋";
                else
                    std::cout << "━━━━";
            std::cout << "━━━┫" << std::endl;
        } else if (i < 8) {
            std::cout << "┃";
            for (int j = 0; j < 8; j++)
                if (j == 2 || j == 5)
                    std::cout << "   ┃";
                else
                    std::cout << "    ";
             std::cout << "   ┃" << std::endl;
        }
    }
    std::cout << "┗";
    for (int i = 0; i < 8; i++)
        if (i == 2 || i == 5)
            std::cout << "━━━┻";
        else
            std::cout << "━━━━";
    std::cout << "━━━┛" << std::endl;
}

int main()
{
    int map[9][9] = {
        0, 0, 1, 0, 0, 0, 6, 0, 0,
        0, 5, 9, 0, 0, 2, 0, 0, 0,
        4, 0, 0, 0, 0, 6, 0, 0, 2,
        0, 0, 0, 8, 7, 0, 0, 1, 0,
        2, 0, 0, 0, 9, 0, 0, 0, 7,
        0, 4, 0, 0, 5, 3, 0, 0, 0,
        8, 0, 0, 5, 0, 0, 0, 0, 6,
        0, 0, 0, 1, 0, 0, 7, 9, 0,
        0, 0, 4, 0, 0, 0, 5, 0, 0,
    };
    print(map);
    sudoku(map);
    print(map);
    return 0;
}


發佈了29 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章