[英]Java Sudoku solver backtracking
我正在尝试构建数独求解器。 我知道我的代码很乱,可能会有更简单的方法来做,但是我想以开始的方式来完成算法。
该算法开始执行我想要的操作(用适合的第一个数字填充空白),但是当到达没有选项的点时,我不知道如何返回并擦除我尝试插入的最后一个数字另一种组合。 但是我不能只删除矩阵中的最后一个数字,因为它可能是算法未放置的数字。
如果有人可以提供帮助,我将非常感激。
public class Backtracking{
public static void Sudoku(int[][] sudokuTable){
if (isAnswer(sudokuTable)){
printSudoku(sudokuTable);
}else{
for (int j = 1; j <=9; j++){
if (canfit(sudokuTable, j)){
addToSudoku(sudokuTable, j);
printSudoku(sudokuTable);
Sudoku(sudokuTable);
}
}
}
}
public static void addToSudoku(int[][] sudokuTable, int n){
int i = 0;
int j = 0;
boolean done = false;
while (i < 9 && !done){
while (j < 9 && !done){
if (sudokuTable[i][j] == 0){
sudokuTable[i][j] = n;
done = true;
}
j++;
}
i++;
}
}
public static void printSudoku(int[][] sudokuTable){
for (int i = 0; i < 9; i++){
for (int j = 0; j < 9; j++){
System.out.print(sudokuTable[i][j] + " ");
}
System.out.println();
}
System.out.println();
}
public static boolean isAnswer(int[][] sudokuTable){
int sum = 0;
for (int i = 0; i < 9; i++){
for (int j = 0 ; j < 9; j++){
if (sudokuTable[i][j] > 9 || sudokuTable[i][j] < 1)
return false;
else
sum++;
}
}
if (sum != 405)
return false;
return true;
}
public static boolean canfit(int[][] sudokuTable, int n){
int i = 0;
int j = 0;
boolean pos = false;
boolean fit = true;
while (i < 9 && !pos){
while (j < 9 && !pos){
if (sudokuTable[i][j] == 0)
pos = true;
else
j++;
}
if (!pos)
i++;
}
for (int k = 0; k < 9; k++){
if (sudokuTable[i][k] == n && k != j)
fit = false;
}
if (fit){
for (int l = 0; l < 9; l++){
if(sudokuTable[l][j] == n && l != i)
fit = false;
}
}
if (fit){
if (i >= 0 && i < 3)
i = 0;
else if (i >=3 && i < 6)
i = 3;
else if (i >=6 && i < 9)
i = 6;
if (j >= 0 && j < 3)
j = 0;
else if (j >=3 && j < 6)
j = 3;
else if (j >=6 && j < 9)
j = 6;
for (int m = i; m < i+3; m++){
for (int o = j; o < j+3; o++){
if (sudokuTable[m][o] == n)
fit = false;
}
}
}
return fit;
}
尝试从Sudoko方法返回true或false。
当isAnswer()
方法返回true
,将打印表。 然后从Sudoko()
方法返回true
。
现在在for循环中,您递归地调用Sudoko()
方法,检查它是否返回true
或false
。 如果返回true
,则表明您的选择是正确的,并且可以找到解决方案,您无需执行其他任何操作。 如果返回false
,则删除使用addToSudoko()
方法设置的数字。 在调用addToSudoko()
方法并继续进行迭代之前,使表addToSudoko()
。
如果您的for循环,循环9次,但没有一个数字有合适的位置,这意味着如果循环结束,则返回false。
希望这可以帮助
实际上,您可以使用数组来回溯移动,每次移动错误时,您都只是开始删除一些移动并尝试其他移动,但是这有一个问题:
假设以下情况是2x2的单元格sudoky:
+----+----++-----+-----+
| 1 | 2 || 3 | 4 |
+----+----++-----+-----+
| 4 | 3 || 1 | 2 |
+====+====++=====+=====+
| 2 | 1 || 4 | 3 |
+----+----++-----+-----+
| 3 | 4 || 2 | 1 |
+----+----++-----+-----+
如果在以下(未解决的)情况下使用算法:
+----+----++-----+-----+
| 1 | || | 4 |
+----+----++-----+-----+
| | || | |
+====+====++=====+=====+
| 2 | || | |
+----+----++-----+-----+
| | 4 || | 1 |
+----+----++-----+-----+
他可能会遇到以下顺序
+----+----++-----+-----+
| 1 | || 2 | 4 |
+----+----++-----+-----+
| | || 2 | |
+====+====++=====+=====+
| 2 | || | |
+----+----++-----+-----+
| | 4 || | 1 |
+----+----++-----+-----+
实际上添加的“ twos”都是错误的,但是当您的算法发现错误的原因是因为在同一列中有2个“ twos”时, 您不知道哪个是错误的 (第一个添加了,第二个添加了) , 或两者?)
正确的回溯算法将像这样工作:
。
for(int i=0; i<81; i++)
array[i] = TryNumber();
。
。
if(SomeNumberNotCorrect())
break; // you know you can stop "tryingnumbers" so you can save on loop executions
。
现在写一个正确的算法来解决数独问题,并且不能在数百万年内运行,这已经很长了,我不能在这里写出来,但是我不认为您选择的方式是最好的。 最好的方法是应用玩家使用的相同策略。 请记住,如果您想让算法以与计算机下棋方式类似的方式来解决数独问题,则算法将比棋类游戏花费更多的时间(实际上,计算机不能分析棋盘动作超过5-6圈) 。 但是实际上数独可以用更快的算法解决。
相反,我过去已经做过一个简单的求解器,您实际上可以尝试应用玩家用来解决它的相同策略:
例如:
当您的求解器不再在Sudoku上找到解决方案时,这仅仅是因为您必须作为玩家开发一种新策略,然后将其应用到您的程序中,总之,您将拥有一个能够解决所有问题的程序。数独(不是很困难,实际上这是有很多免费的数独求解器的原因)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.