个人项目:生成数独终局并求解
注:这周时间不太充裕,内容相对较简略,详细内容之后更新。
四.设计实现
2.编码实现
(2)求解数独模块设计实现
求解数独我首先尝试了DLX算法,但写到一半发现时间成本可能过高,因此转变成了基本的回溯算法,如果之后时间有充裕再考虑进一步优化成DLX算法。
回溯算法主要由SolveSoduku函数实现。
首先以ifstream的getline方法读入每行(ifstream正常读入的话遇空格、换行停止),对读入的每行数据进行处理,存入数组矩阵grid中。同时记录行数,当行数达到9,说明已经读入了一个完整的矩阵,进行回溯求解。
对每个完整矩阵的回溯求解以SolveSingleSoduku函数处理。标识矩阵中某一点是否被访问,一开始我用了非常繁复的方法,后来通过查阅资料1发现,可以通过设置一个vis数组进行实现:
使用vis[3][10][10]数组来标记:其中第一维中0表示行、1表示列、2表示九宫格;第二维中表示在第几个行、列或九宫格中;第三维表示其中的某个数字,如果该数字被填入了,vis值置1,否则置0。
因此,对于一个数独的具体求解就可以转化为:顺序搜索整个盘面数组grid,找到未填入数的格点(即数值=0),for循环1-9尝试放入数,继续向后填数,若最终整个棋盘都被填满,置is_found为true进行返回,得到填数方法的一个可行解。如果搜到某一个点,对于1-9都无法填入格中,则说明之前填写的数字出现了错误,向前回溯,直到找到可行解,is_found为true全部返回为止。
具体回溯过程代码如下:
bool is_search=false;
//遍历1-9
for (int i = 1; i <= 9; i++)
{
//若未访问
if (vis[0][row][i] == 0
&& vis[1][col][i] == 0
&& vis[2][row / 3 * 3 + col / 3][i] == 0)
{
SetVis(row, col, i, SetVisit);//置访问
grid[row][col] = i + '0';
is_search=true;
//回溯
SolveSingleSudoku(row, col);
}
if(is_search)//若一个点被搜索过
{
is_search=false;
if (is_found)//找到了即返回
return;
//重置
SetVis(row, col, i, CancelVisit);
grid[row][col] = '0';
}
}
最终,找到可行解将grid填满,写入缓冲,清除vis数组访问,行计数器置0,继续处理下一矩阵。
https://blog.csdn.net/weixin_40629184/article/details/84958219 ↩︎
来源:CSDN
作者:HoperEdeiDeixai
链接:https://blog.csdn.net/Neubeginn/article/details/103933583