数独是一个很经典的问题,由于数独的规模很小,暴力破解数独也是一个很不错的方法!我就是采用暴力破解的办法去寻找数独的解,在求解的过程中按照人类的思维大大减少了搜索路径的数量!
我设置了一个标记,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;
}