编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
- 数字
1-9
在每一行只能出现一次。- 数字
1-9
在每一列只能出现一次。- 数字
1-9
在每一个以粗实线分隔的3x3
宫内只能出现一次。(请参考示例图)数独部分空格内已填入了数字,空白格用
'.'
表示。
回溯法:
我么创建数组来判断数字是否出现, 我们可以填入的数为1~9, 所以我们创建三个数组表示行,列和3*3的小方格
bool r[i][k];//表示第i行是否出现 k + 1
bool c[j][k];//表示第j列是否出现 k + 1
bool rc[i/3][j/3][k];//表示第(i/3, j/3)个九宫格是否出现 k + 1
我们首先对整个数独数组进行遍历,当我们遍历到第 i 行第 j 列的位置:
vector<pair<int, int>>v;//其中pair<int, int> 用来存还没有填入数字的<i, j> 位置
如果该位置是一个 '.',那么我们将其加入容器,用来进行递归操作
如果该位置是一个数字 x,那么我们要进行如下操作,表示该数字出现已经在i行,j列和(i/3, j/3)出现过。
int k = x - 1;
r[i][k] = true;
c[j][k] = true;
rc[i/3][j/3][k] = true;
当我们初始化原有数据后,进行遍历容器v,从v.begin()开始递归遍历,当递归到第 i 行第 j 列的位置时,我们枚举填入的数字 x。根据题目的要求,数字 x 不能和当前行、列、九宫格中已经填入的数字相同也就是:
int k = x - 1;
r[i][k] = false;
c[j][k] = false;
rc[i/3][j/3][k] = false;
以上三个值为false时,将x填入第 i 行第 j 列,当我们填入了数字 x 之后,我们要将上述的三个值都置为 true,并且继续对下一个空白格位置进行递归。在回溯到当前递归层时,我们还要将上述的三个值重新置为 false。
class Solution {
private:
bool r[9][9];
bool c[9][9];
bool rc[3][3][9];
bool flag;
vector<pair<int, int>>v;
public:
void dfs(vector<vector<char>>& board, int index) {
if(index == v.size()) {
flag = true;
return;
}
int i = v[index].first;
int j = v[index].second;
for(int k = 0; k < 9 && !flag; k++) {
if(!r[i][k] && !c[j][k] && !rc[i/3][j/3][k]) {
r[i][k] = c[j][k] = rc[i/3][j/3][k] = true;
board[i][j] = k + '0' + 1;
dfs(board, index + 1);
r[i][k] = c[j][k] = rc[i/3][j/3][k] = false;
}
}
}
void solveSudoku(vector<vector<char>>& board) {
memset(r, false, sizeof(r));
memset(c, false, sizeof(c));
memset(rc, false, sizeof(rc));
flag = false;
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
if(board[i][j] == '.') {
v.push_back(pair<int, int>(i, j));
}
else {
int k = board[i][j] - '0' - 1;
r[i][k] = c[j][k] = rc[i/3][j/3][k] = true;
}
}
}
return dfs(board, 0);
}
};