我一直在看这段代码几个小时,我无法弄清楚它是如何工作的。有人可以详细解释递归是如何使用这些函数的吗?请记住,我是编程新手。
让我最困惑的部分是如何反复调用solve()?难道它不会在它到达拼图之后停止[row] [col] = 0?
顺便说一下,这是工作代码。
编辑:谢谢你的回答!但我不知道它在哪里回溯。void solve(int row, int col) throws Exception
{
if(row > 8)
{
throw new Exception( "Solution found" ) ;
}
if(puzzle[row][col] != 0)
{
next(row, col);
}
else
{
for( int num = 1; num < 10; num++ )
{
if( checkHorizontal(row,num) && checkVertical(col,num) && checkBox(row,col,num) )
{
puzzle[row][col] = num ;
next( row, col ) ;
}
}
puzzle[row][col] = 0 ;
}
}
public void next( int row, int col ) throws Exception
{
if( col < 8 )
{
solve(row, col + 1) ;
}
else
{
solve(row + 1, 0) ;
}
}
答案 0 :(得分:1)
next
函数可以描述为查找第一个空闲字段的函数,并从该字段开始求解过程。
实际的递归就是一个简单的回溯(http://en.wikipedia.org/wiki/Backtracking)。使用某些伪代码可能更容易掌握一般方案:
Solution findSolution(Board board) {
if (board.isSolved()) return solutionFor(board);
// An "action" here refers to placing any number
// on any free field
for (each possible action) {
do the action // That is: place a number on a free field
// The recursion:
Solution solution = findSolution(board);
if (solution != null) return solution;
// No solution found
UNdo the action // That is: remove the number from the field
// Now the loop continues, and tries the
// next action...
}
// Tried all possible actions, none did lead to a solution
return null;
}
通常,人们会用两个嵌套的for循环确定这些“动作”:
for (each free field f)
{
for (each number n in 1..9)
{
place 'n' on 'f'
try to find solution
remove 'n' from 'f'
}
}
在这种情况下,外部循环在next
函数中有些“隐藏”。
在这种情况下,对于数独,这种特殊的回溯实现可能效果不佳。它可能需要几万亿年才能找到解决方案,因为它有很多可能性。但这基本上取决于check*
方法实现的“聪明”程度。快速检测(部分)解决方案已经无效的情况非常重要。也就是说,无论你是否有无法找到解决方案的情况。例如,当3x3-sqares之一的两个单元格包含相同的数字时,情况已经“无效”。例如,可以通过显式存储仍然可用的数字来避免这种情况,但当然代码会变得更加复杂。