数独求解

数独是一个很经典的问题,由于数独的规模很小,暴力破解数独也是一个很不错的方法!我就是采用暴力破解的办法去寻找数独的解,在求解的过程中按照人类的思维大大减少了搜索路径的数量!

我设置了一个标记,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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值