前几天笔者外出培训,刚刚学习了深度优先搜索,突然想到了数独的求解其实也可以用深搜实现,遂写了数独求解器与生成器。
1 数独求解器
1.1 预备
一开始,当然是头文件~
#include <iostream>
#include <stdlib.h>
接下来,是变量定义区
int sudoku[10][10];
//题目存储区
int row[10][10],column[10][10],block[4][4][10];
/*标记行、列、九宫格内某数字是否被使用过,例如row[4][7]=1代表第4行已有数字7*/
int known[10][10];
/*标记某单元格是否是题目所给数字,1代表题目中的数字*/
/*以上数组下标均从1开始使用*/
1.2 核心算法——深搜
相信学过深搜的朋友应该知道,深搜的过程含搜索与回溯两步。
void search(int x,int y){
if (known[x][y]){
search((9*x+y-9)/9+1,y%9+1); //如果是题目中的数字则直接搜索下一个单元格,这里一并处理了y=9即现在所处单元格在行末的情况
}
else{
if (x==10 && y==1) { //已经填完所有的数并合法
print(); //打印输出
exit(0); //找到一个解就退出。若欲找出所有的解,将此行去掉即可
}
else
for (int i=1;i<=9;i++){ //枚举填数1~9
if (row[x][i]==0 && column[y][i]==0 && block[(x-1)/3+1][(y-1)/3+1][i]==0){ //判断此数是否合法。九宫格计算略显复杂
sudoku[x][y]=i;
row[x][i]=1;
column[y][i]=1;
block[(x-1)/3+1][(y-1)/3+1][i]=1;
search((9*x+y-9)/9+1,y%9+1);//填入下一个数,计算方法同第三行
sudoku[x][y]=0;
row[x][i]=0;
column[y][i]=0;
block[(x-1)/3+1][(y-1)/3+1][i]=0;//回溯:恢复之前的状态
}
}
}
}
以上代码,一气呵成。
1.3 输出
为获得较好的视觉效果,笔者决定,输出格式用“-”和“|”画出单元格边界,用“=”和“||”表示九宫格边界和题目的边界。具体效果如下图所示:
简单。马上给出代码实现:
void print(){
cout<<" 1 2 3 4 5 6 7 8 9 "<<endl;//列号
cout<<" ===================================== "<<endl;
for (int i=1;i<=9;i++){
cout<<i<<"|| ";//行号
for (int j=1;j<=9;j++){
if (j%3!=0) cout<<sudoku[i][j]<<" | ";//非九宫格边界
else cout<<sudoku[i][j]<<" || ";//九宫格边界
}
cout<<endl;
if (i%3!=0)cout<<" ------------------------------------- "<<endl;//非九宫格边界
else cout<<" ===================================== "<<endl;//九宫格边界
}
}
当然笔者并未满足,整天对着黑白的控制台也会疯掉的。百度了一下C++如何使输入输出带上颜色之后,笔者改进了输出函数: