【第三篇】数独终局

亡梦爱人 提交于 2020-01-11 12:46:22


注:这周时间不太充裕,内容相对较简略,详细内容之后更新。

四.设计实现

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,继续处理下一矩阵。


  1. https://blog.csdn.net/weixin_40629184/article/details/84958219 ↩︎

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!