在这篇文章中,我将介绍一种使用回溯的数独求解算法。如果你不知道回溯,那么只需刷过上一篇文章。
Sudoku是一个9x9矩阵,填充数字1到9,每个行,列和子矩阵(3x3)的每个数字都是1到9.我们提供了部分填充的9x9矩阵,必须填充其中每个剩余的细胞。例如,下面给出了数独问题。
其解决方案如下。
您可以看到每个行,列和子矩阵(3x3)包含从1到9的每个数字。因此,我们还可以得出结论,如果数独满足以下任何条件,则认为数据被错误填充:
- 任何行包含多次相同的数字。
- 任何列都包含多次相同的数字。
- 任何3x3子矩阵都具有不止一次的相同数字。
在回溯中,我们首先从一个子解决方案开始,如果这个子解决方案没有给我们一个正确的最终答案,那么我们回过头来改变我们的子解决方案。我们将以类似的方式解决我们的数独。我们将遵循的步骤是:
- 如果没有未分配的单元格,则数独已经解决。我们将回归真实。
- 否则,我们将使用1到9之间的数字填充未分配的单元格,以便在任何行,列或3x3子矩阵中不存在冲突。
- 现在,我们将尝试填充下一个未分配的单元格,如果这成功发生,那么我们将返回true。
- 否则,我们将返回并更改用于填充单元格的数字。如果没有满足需要的数字,那么我们将返回false,因为没有这个数独的解决方案。
所以,让我们编写代码吧。
class Sudoku{ private static final int SIZE = 9; private static int[][] matrix = { {6,5,0,8,7,3,0,9,0}, {0,0,3,2,5,0,0,0,8}, {9,8,0,1,0,4,3,5,7}, {1,0,5,0,0,0,0,0,0}, {4,0,0,0,0,0,0,0,2}, {0,0,0,0,0,0,5,0,3}, {5,7,8,3,0,1,0,2,6}, {2,0,0,0,4,8,9,0,0}, {0,9,0,6,2,5,0,8,1} }; private static void printSudoku() { for(int i=0;i
代码说明
最初,我们只是为Sudoku制作一个矩阵,并用0填充未分配的单元格。因此,矩阵包含Sudoku问题,值为0的单元格是空白单元格。
print_sudoku() →这只是打印矩阵的功能。
number_unassigned →此函数找到一个空单元格,并使变量'row'和'col'等于该单元格的索引。在C中,我们使用指针来改变传递给该函数的变量(row,col)的值(通过引用传递)。在Java和Python中,我们返回一个包含这些值的数组(或Python列表)。所以,这个函数告诉我们是否有任何未分配的单元格。如果有任何未分配的单元格,那么此函数也会告诉我们该单元格的索引。
is_safe(int n, int r, int c)→此函数检查我们是否可以将值'n'放入单元格(r,c)中。我们这样做是首先检查行'r'中是否有任何单元格的值为'n'或不是 - if(matrix[r][i] == n)。然后我们检查在'c'列中是否有任何值为'n'的单元格 - if(matrix[i][c] == n)。最后,我们正在检查子矩阵。 (r/3)*3 给出了行r的起始索引。例如,如果'r'的值是2,那么它在从(0,0)开始的子矩阵中。同样,我们得到了起始列的值(c/3)*3。因此,如果一个单元格是(2,2),那么这个单元格将在一个从(0,0)开始的子矩阵中,我们得到这个值(c/3)*3和(r/3)*3。在获得起始索引之后,我们可以轻松地遍历子矩阵以检查我们是否可以将值'n'放在该子矩阵中。
solve_sudoku()→这是解决数独并使用回溯的实际功能。我们首先通过使用该number_unassigned函数检查是否有任何未分配的单元格 ,如果没有未分配的单元格,则解决数独。 number_unassigned 函数还给出了空单元的索引。因此,如果有任何空白单元格,那么我们将尝试用1到9之间的值填充此单元格。我们将使用它 is_safe 来检查是否可以填充该单元格中的特定值。找到一个值后,我们将尝试解决数独的其余部分solve_sudoku。如果此值无法解决其余问题,我们将返回并尝试此单元格的其他值matrix[row][col]=0;。循环将尝试单元格中的其他值。
整理不易,请大家多多收藏加关注 ,谢谢。