Write a program to solve a Sudoku puzzle by filling the empty cells.
Empty cells are indicated by the character'.'.
You may assume that there will be only one unique solution.
A sudoku puzzle...
...and its solution numbers marked in red.
题意:填写数独,假设题目只有一种解
思路:大致的方向是,遍历数组,试探性的往非数字处填数,保证填写的数字在行、列、小正方形内都是合法的。这题的思想和n queens很像。很自然的将整个代码分为三部分(第一、二部分合并也行,这里只是为了好理解),第一部分调用,第二部分 回溯函数的主体,第三部分判断填写的数是否合法。主要说明第二、三部分。
1)填写数字必须是在空的地方即表中' . ' 处。如何填写了?用1~9总共九个数一个个试探,如果当前填写数字合法,我们考虑下一列的数(递归),若是不合法,就将刚才填写的数还原;若表中当前位置是数字,直接考虑下一列。那终止条件是什么呢?当 i=9 即遍历完整个矩阵了(因为 i=0开始遍历),返回true。若是i !=9 但每一行都遍历完了,怎么办?此时,我们只需转到下一行重新开始遍历即可。对于回溯函数的返回值类型为什么是bool型,zxzxy1988给出的解释是:backtracking的递归函数,怎么能没有返回值呢?!因为要判断递归的方案正确与否,所以这里的递归一定是有返回值的(除非是combination那种没有正确错误概念的backtracking)!
2)如何判断填写的数是否合法?判断该处的数字是否合法,需考虑三个方面:所在列、所在行、所在小矩阵。对该行,只需从左到右的遍历,寻找是否有等于该数的元素(当然,其本身所在位置除外),若有则直接返回false,若没有则判断其他情况,列和小矩阵的情况这判断行类似。
代码如下:
1 class Solution { 2 public: 3 void solveSudoku(vector<vector<char> > &board) 4 { 5 if(board.empty()||board.size() !=9||board[0].size() !=9) 6 return; 7 solveSudokuDFS(board,0,0); 8 } 9 10 bool solveSudokuDFS(vector<vector<char>> &board,int i,int j) 11 { 12 if(i==9) return true; 13 if(j>=9) return solveSudokuDFS(board,i+1,0); 14 if(board[i][j]=='.') 15 { 16 for(int k=1;k<=9;++k) 17 { 18 board[i][j]=(char)(k+'0'); 19 if(isValid(board,i,j)) //两个if可以合并 20 { 21 if(solveSudokuDFS(board,i,j+1)) 22 return true; 23 } 24 board[i][j]='.'; 25 } 26 } 27 else 28 { 29 return solveSudokuDFS(board,i,j+1); 30 } 31 return false; 32 } 33 34 bool isValid(vector<vector<char>> &board,int i,int j) 35 { 36 for(int col=0;col<9;++col) 37 { 38 if(col !=j&&board[i][j]==board[i][col]) 39 return false; 40 } 41 for(int row=0;row<9;++row) 42 { 43 if(row !=i&&board[i][j] ==board[row][j]) 44 return false; 45 } 46 47 for(int row=i/3*3;row<i/3*3+3;++row) 48 { 49 for(int col=j/3*3;col<j/3*3+3;++col) 50 { 51 if((row !=i || col !=j)&&board[i][j]==board[row][col]) 52 return false; 53 } 54 } 55 return true; 56 } 57 };
解题时参考了Code Gander和Grandyang的博客。