我创建这个新线程而不是仅仅阅读之前给出的这个特定问题的答案的原因是我觉得我只是不完全理解它背后的整个想法。我似乎无法理解整个回溯的概念。所以我需要充分理解回溯,然后解决特定的数独问题。
到目前为止,我所理解的是,回溯是一种返回的技术,在(例如)递归流程中,如果人们发现在当前状态之前做出的决定导致了死胡同。所以你回去试试别的,然后再继续。
因此,在我的数独示例中,我选择了第一个空单元格并尝试从 {1...9} 中填充一个自然数,该自然数与众所周知的数独规则不冲突。现在我对下一个空单元格做同样的事情,直到我没有插入有效数字而不会发生冲突。据我了解,这应该是回溯发挥作用的地方。但是怎么做?如果我使用递归返回最后写入的单元格,算法将再次填写数字,继续并最终陷入无限循环。
因此,我在 Internet 上搜索了提示,发现这是一个有据可查且经常解决的问题。然而,许多解决方案声称使用回溯,即使我面前有源代码,我也看不出他们是如何或在哪里做的。
例如:Java 中的数独求解器,使用回溯和递归或http://www.heimetli.ch/ffh/simplifiedsudoku.html
这是我的(不工作)源代码:
private boolean isSolvable( Sudoku sudoku, int row, int col ){
//if the method is called for a row > 8 the sudoku is solved
if(row > 8)
return true;
//calculate the next cell, jump one row if at last column
int[] nextCell = (col < 8) ? new int[]{row,col+1} : new int[]{row+1,0};
//check if the current cell isWritable() that is if it is not a given cell by the puzzle
//continue recursively with the next cell if not writable
if(!sudoku.isWritable(row, col))
isSolvable(sudoku, nextCell[0], nextCell[1]);
else{
//set the current cell to the lowest possible not conflicting number
for(int i=1; i< 10; i++){
if(!conflictAt(sudoku, row, col, i)){
sudoku.setValue(row, col, i);
//continue recursively with the next cell
isSolvable(sudoku, nextCell[0], nextCell[1]);
}
}
}
return false;
}
现在我不知道如何继续。如何实施回溯或者我已经实施了吗?这似乎是一个愚蠢的问题,但我真的没有看到上面链接中提到的源代码中有更多的回溯。
编辑:最终(工作)版本:
private boolean isSolvable( Sudoku sudoku, int row, int col ){
//if the method is called for a row > 8 the Sudoku is solved
if(row > 8)
return true;
//if the cell is not writable, get the next writable cell recursively
if(!sudoku.isWritable(row,col))
return isSolvable(sudoku, (col<8) ? row : row + 1, (col<8) ? col + 1 : 0);
//brute forcing for solution
for(int i=1; i<=9; i++){
if(!conflictAt(sudoku, row, col, i)){
sudoku.setValue(row, col, i);
if(isSolvable(sudoku, (col<8) ? row : row + 1, (col<8) ? col + 1 : 0)) return true;
}
}
sudoku.setValue(row, col, 0);
return false;
}