Java数独求解器forwardCheck递归仅遍历第一行就终止问题求助
问题原因分析
- 定义域大小为1的分支缺少递归调用:你代码中当
valueDomain.size() == 1时,仅给当前单元格赋值,没有继续调用forwardCheck向下递归填充后续的单元格。你提供的测试输入第一行最后一个空位的定义域恰好只有1个有效值,赋值后逻辑直接跳出方法,自然就停在第一行。 - 递归返回值未被正确处理:
forwardCheck方法设计为填充完成返回true、填充失败返回false,但你在调用递归forwardCheck(board)后没有接收返回值。如果递归已经完成全部填充(返回true),当前层应该直接返回true终止逻辑,否则需要触发回溯。 - 未做错误路径的回溯操作:当你选中的随机值对应的递归路径走不通时,没有把当前单元格的值重置为0,会导致错误的赋值残留,影响后续路径的判断。
- 单条路径尝试逻辑错误:非强制赋值(定义域大于1)的场景下,你仅随机选了一个值尝试,没有遍历定义域内所有候选值,一旦选到的数值对应的路径走死,整个递归直接失败。
- 空定义域分支逻辑错误:当
valueDomain.size() == 0时,说明当前路径无解,应该直接返回false通知上层回溯,不需要额外调用backtrack方法,否则会打乱递归逻辑。
修复后的核心代码
public static boolean forwardCheck(Cell[][] board) { boolean isEmpty = true; int row = -1; int col = -1; LinkedList<Integer> valueDomain = null; // 查找第一个空单元格逻辑保持不变 for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (board[i][j].getValue() == 0) { row = i; col = j; valueDomain = getCellDomains(board, row, col); isEmpty = false; break; } } if (!isEmpty) { break; } } // 所有单元格填充完成,返回成功 if (isEmpty) { return true; } // 当前单元格无可用候选值,当前路径失败 if (valueDomain.size() == 0) { return false; } // 遍历所有候选值,可提前打乱valueDomain顺序保留原随机选择的特性 for (int candidate : valueDomain) { if (isValid(board, row, col, candidate)) { // 尝试赋值 board[row][col].setValue(candidate); // 递归填充后续单元格,递归返回true说明全量填充完成,直接向上返回 if (forwardCheck(board)) { return true; } // 递归失败,回溯重置当前单元格 board[row][col].setValue(0); } } // 所有候选值均不可用,当前路径失败 return false; }
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

