我正在尝试使用递归回溯算法解决任何给定的数独难题.我的数独求解器有两个问题.首先,它解决了难题,但它会递归备份并在此过程中将其解散(解决约4718次递归,并出于某种原因再进行10000次左右的备份).第二个问题是由于我试图解决此问题.找到解决方案后,我将使用全局矩阵解决方案来保存该解决方案,并使用以下形式的isSolved方法验证是否已找到它:
public static boolean isSolved(int[][]puzzle){
for(int i = 0; i<9; i++){ //y rotation
for(int j = 0; j<8; j++){
if(puzzle[i][j]==0){
return false;
}
}
}
return true;
}
在我的难题中,其中有一个0的块等效于它为空.然而,这似乎也被重置了,尽管我找不到重置位置.在我应该看的地方有什么指示或建议或指示吗?
这是我的求解方法,我已经注释了重要的行
public static int[][] solve(int[][]puzzle, int x, int y){
System.out.println("RecrDepth: " + recDepth);
recDepth++;
//using backtracking for brute force power of the gods(norse cause they obviously most b.a.
ArrayList<Integer> list = new ArrayList<Integer>();
//next for both x and y
int nextx = getNextx(x);
int nexty = getNexty(x, y);
while(puzzle[y][x] != 0){ //progress until blank space
x = nextx;
y = nexty;
if(isSolved(puzzle)){
System.out.println("resetting solution improperly");
solution = puzzle;
return puzzle;
}
nextx = getNextx(x);
nexty = getNexty(x, y);
}
for(int i = 1; i<10; i++){
if(isTrue(puzzle, y, x, i)) //isTrue checks column, row and box so we dont go down unnecessary paths
list.add(i);
}
for(int i=0; i<list.size(); i++){ //iterating through options in open squre recursing for each one
puzzle[y][x]= list.get(i);
if(isSolved(puzzle)){
System.out.println("Resetting Solution"); //appears to reset solution here but only once that I see in print out
solution = puzzle;
return puzzle;
}
System.out.print("=");
puzzle = solve(puzzle, nextx, nexty);
puzzle[y][x] = 0;//clear spot upon backtracking THIS WAS WHAT I WAS MISSIN
}
return puzzle;
}
再次感谢您的时间,完整的代码和readin文件位于github上的wechtera / ssolverOO,它是ssolver.java文件,而readin是ssolverin.txt.
解决方法:
如果我正确理解了您的代码,则问题似乎出在递归实现不充分的事实上,即即使找到正确的答案,您的程序仍会继续循环执行最后一个for循环.
假设在第一个空白方块中,正确的数字是4.但是,程序正在考虑的数字列表(在该时间点)可能是{2,4,6,7}.在这种情况下,似乎会发生的是,它将在4找到确实正确的答案,并且将生成正确的输出.但是它仍然会检查6和7.由于(当然)它将找不到任何答案,因此它将输入保留为空白,从而为您提供了原始的电路板.
现在,尽管我认为您在某种程度上具有设置全局变量以存储实际答案的正确想法.问题是您没有生成数组的副本,而只是复制了指向它的指针(引用).
您可以简单地创建一个copy方法来实际复制整个数组,但是请记住,即使您生成正确的答案,您的算法仍然会不必要地循环并浪费时间.
作为参考,这是我编写的Solve方法,其中的isValid()方法等效于您的isTrue():
public static final int SIZE = 9;
public static boolean solve(int[][] s) {
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
if (s[i][j] != 0) {
continue;
}
for (int num = 1; num <= SIZE; num++) {
if (isValid(num, i, j, s)) {
s[i][j] = num;
if (solve(s)) {
return true;
} else {
s[i][j] = 0;
}
}
}
return false;
}
}
return true;
}