You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 07:57:02