数独是一种传统益智游戏,你需要把一个 9×99×9 的数独补充完整,使得图中每行、每列、每个 3×33×3 的九宫格内数字 1∼91∼9 均恰好出现一次。
请编写一个程序填写数独。
输入格式
输入共 99 行,每行包含一个长度为 99 的字符串,用来表示数独矩阵。
其中的每个字符都是 1∼91∼9 或 ..(表示尚未填充)。
输出格式
输出补全后的数独矩阵。
数据保证有唯一解。
输入样例:
.2738..1.
.1...6735
.......29
3.5692.8.
.........
.6.1745.3
64.......
9518...7.
.8..6534.
输出样例:
527389416
819426735
436751829
375692184
194538267
268174593
643217958
951843672
782965341
本题目还是老套的搜索题目
其中行遍历,列遍历,以及九宫格遍历
行遍历代码:
for(int i=0;i<9;i++)
if(a[x][i]>47&&a[x][i]<58)//字符串检查1-9
st[a[x][i]^48]=true;
思路是什么呢,就是两个变量一个表示行一个表示列然后,固定一个,遍历一个,然后将开一个bool类型的数组如果当前位置以及数字,就把当前位数和数字都一并存入
九宫格遍历
int sx=x/3*3,sy=y/3*3;一个元素所在九宫格
什么这样计算?
- 除以3:我们首先将行号或列号除以3,这是因为每个3x3的小方格在数独中占据3行和3列。
- 乘以3:然后我们将得到的结果乘以3,这样可以将行号或列号调整回原来格子的起始行号或列号。
例子
假设我们有一个坐标 (x, y) = (3, 3)
:
-
对于行号
x
:x / 3 = 3 / 3 = 1
,这表示第3行是第2个3行组(从0开始计数)。1 * 3 = 3
,这表示第2个3行组的起始行号是3。
-
对于列号
y
:y / 3 = 3 / 3 = 1
,这表示第3列是第2个3列组(从0开始计数)。1 * 3 = 3
,这表示第2个3列组的起始列号是3。
因此,(x, y) = (3, 3)
所在的3x3九宫格的左上角坐标确实是 (2, 2)
,而不是 (3, 3)
。这是因为 (2, 2)
是该九宫格的左上角顶点,而 (3, 3)
是该九宫格内的一点。
总结
sx = x / 3 * 3
计算的是当前行所在的3x3九宫格的起始行号。sy = y / 3 * 3
计算的是当前列所在的3x3九宫格的起始列号。
这种计算方法适用于数独的任何位置,可以准确地找到任何单元格所在的3x3九宫格的左上角坐标。
行号: 0 1 2 3 4 5 6 7 8
列号:
0 1 2 3 4 5 6 7 8
0 +---+---+---+---+---+---+---+---+
1 +---+---+---+---+---+---+---+---+
2 +---+---+---+---+---+---+---+---+
3 +---+---+---+---+---+---+---+---+
4 +---+---+---+---+---+---+---+---+
5 +---+---+---+---+---+---+---+---+
6 +---+---+---+---+---+---+---+---+
7 +---+---+---+---+---+---+---+---+
8 +---+---+---+---+---+---+---+---+
如果x=2,y=3那么sx=0,sy=3;满足
这个做法目的就是为了将初始坐标定在九宫格最上边的位置
接下来典型的九宫格遍历
int sx=x/3*3,sy=y/3*3;//这个步骤是把起始坐标为九宫格最左边的位置
for(int i=sx;i<sx+3;i++)
for(int j=sy;j<sy+3;j++)
if (a[i][j] > 47 && a[i][j] < 58)
st[a[x][i]^48] = true;
遍历完成之后就要进行所有情况预演,也就是搜索本体
for(int i=1;i<N;i++)
if(!st[i]){//如果没走过
a[x][y] = i^48; //将有可能的数字存入
if(dfs(x+1,y))return true;//表示当前位置进行一个判断能行的话就进行下一步遍历
}
a[x][y] = '.';//回溯
return false;//如果尝试了所有可能的数字,都无法找到有效的解决方案,那么返回 false。