Write a program to solve a Sudoku puzzle by filling the empty cells.
A sudoku solution must satisfy all of the following rules:
- Each of the digits
1-9
must occur exactly once in each row. - Each of the digits
1-9
must occur exactly once in each column. - Each of the the digits
1-9
must occur exactly once in each of the 93x3
sub-boxes of the grid.
Empty cells are indicated by the character '.'
.
A sudoku puzzle...
...and its solution numbers marked in red.
Note:
- The given board contain only digits
1-9
and the character'.'
. - You may assume that the given Sudoku puzzle will have a single unique solution.
- The given board size is always
9x9
.
题目解数独
无脑回溯。重点在于使用一些技巧让代码更快。目前能想到的就是使用位运算。可以很方便快速的检测是否重复。代码如下:
void solveSudoku(char** board, int boardRowSize, int *boardColSizes) {
int num;
int map[10] = { 0,1,2,4,8,16,32,64,128,256 };
int tmpR[9] = { 0 };//每一行的占用情况
int tmpC[9] = { 0 };//每一列的占用情况
int tmpI[3][3] = {};//每个格子的占用情况
int emptyBox[9 * 9];//空格子
char tryStack[9 * 9] = { 0 };//尝试填充数字的栈
int l = 0;//空格子数量
int finish = 0;//已完成格子数
int i;
//统计所有空格子,并初始化已有数字的bitmep影响
for (i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) {
if (board[i][j] == '.') {
emptyBox[l++] = ((i << 4) | (j));
continue;
}
num = board[i][j] - '0';
tmpR[i] |= map[num];
tmpC[j] |= map[num];
tmpI[i/3][j/3] |= map[num];
}
}
if (l == 0) {//不需要解
return;
}
while (finish != l && finish >= 0) {
int tryIndex = finish;
int tryBoxX = (emptyBox[tryIndex] >> 4);
int tryBoxY = (emptyBox[tryIndex] & 0x0f);
if (tryStack[tryIndex] != 0) {//清除掉旧数字的影响
tmpR[tryBoxX] ^= map[tryStack[tryIndex]];
tmpC[tryBoxY] ^= map[tryStack[tryIndex]];
tmpI[tryBoxX/3][ tryBoxY/3] ^= map[tryStack[tryIndex]];
board[tryBoxX][tryBoxY] = '.';
}
for (i = tryStack[tryIndex] + 1; i <= 9; ++i) {//从下一个数字开始尝试
if (((tmpR[tryBoxX] | tmpC[tryBoxY] | tmpI[tryBoxX/3][ tryBoxY/3])&map[i]) == 0) {//有效值
//更新bitmap 继续下一个格子
board[tryBoxX][tryBoxY] = '0' + i;
tmpR[tryBoxX] |= map[i];
tmpC[tryBoxY] |= map[i];
tmpI[tryBoxX/3][ tryBoxY/3] |= map[i];
tryStack[tryIndex] = i;
++finish;
break;
}
}
if (i == 10) {//回滚
tryStack[tryIndex] = 0;
--finish;
}
}
}
note: 实际刚写完这个题目的时候想过要做一个拍照解数独的小程序。可惜一年多了还没有动手。现在排上计划。学习和开发过程将在"拍照解数独"分类中进行记录。敬请期待!