boxmoe_header_banner_img

欢迎来到YaeMiko小站

加载中

文章导读

数独的递归与回溯


avatar
Samele 2025-05-10 24

另外一道经典的递归与回溯问题。

数独

背景:

标准数独使用9×9的方格,被划分为9个3×3的宫(称为“粗线宫”)。
‌数字填充‌: 需根据已知数字,推理出剩余空格数字,范围限定1-9,且满足:
‌行唯一‌: 每行包含1-9不重复
‌列唯一‌: 每列包含1-9不重复
‌宫唯一‌: 每个3×3宫内包含1-9不重复
‌解的唯一性‌: 合格题目仅有一个解。

一个经典的递归问题,

解题思路:

规则:每行1-9,每列1-9,每个正方格1-9不重复。

第一步:

数据规则,创建一个9×9的数组,将已知的数字标注,未知的数字用0代替

确认退出条件:

当整个数组不存在0时,即判定为退出条件

递归条件:判断一个格子 复核放置标准,放置该数字,同时递归调用,寻找下一个为0的格子

参考代码如下:

public class Sudoku {

    public static void main(String[] args) {


        int[][] board = {
                {0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 3, 0, 8, 5},
                {0, 0, 1, 0, 2, 0, 0, 0, 0},

                {0, 0, 0, 5, 0, 7, 0, 0, 0},
                {0, 0, 4, 0, 0, 0, 1, 0, 0},
                {0, 9, 0, 0, 0, 0, 0, 0, 0},

                {5, 0, 0, 0, 0, 0, 0, 7, 3},
                {0, 0, 2, 0, 1, 0, 0, 0, 0},
                {0, 0, 0, 0, 4, 0, 0, 0, 9}
        };


        new Sudoku().solution(board);
    }

    //递归调用方法
    public void solution(int[][] board) {
        if (exit(board)) {//达成退出条件:打印结果,返回
            print(board);
            return;
        }
        //递归条件:遍历格子中所有为0的格子
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                if (board[i][j] == 0) {//值为0,需要填补的值
                    //从1-9中挑选一个数字进行测试
                    for (int k = 1; k <= 9; k++) {
                        //测试这个数字是否能放置到该位置
                        if (isValid(board, i, j, k)) {//有效!
                            //放置这个数字!
                            board[i][j] = k; 
                            //递归调用,寻找下一个需要填入的位置:值为0的格子
                            solution(board);
                            //回溯时,将这个格子重新调整为0
                            board[i][j] = 0;//恢复参数
                        }
                    }
                    //1-9都不能解决问题,不能继续填写了,直接返回,向前回溯
                    return;
                }

            }
        }

    }

    /**
     * 解决方案
     *
     * @param board 面板
     */
    public boolean isValid(int[][] board, int row, int col, int num) {
        //每一行的元素不能重复
        for (int i = 0; i < board.length; i++) {
            if (board[row][i] == num) return false;
        }
        //每一列的元素不能重复
        for (int i = 0; i < board.length; i++) {
            if (board[i][col] == num) return false;
        }
        //每个正方形不能重复
        return isBoxValid(board, row, col, num);
    }
    //判断正方形格子里数值没有重复
    public boolean isBoxValid(int[][] board, int row, int col, int num) {
        int startRow = (row / 3) * 3;
        int startCol = (col / 3) * 3;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (board[startRow + i][startCol + j] == num) {
                    return false;
                }
            }
        }
        return true;
    }


    /**
     * 退出条件,当面板中没有0的时候退出
     *
     * @param board 面板
     * @return 是否退出
     */
    public boolean exit(int[][] board) {
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                if (board[i][j] == 0) {
                    return false;
                }
            }
        }
        return true;
    }
    //打印结果
    public void print(int[][] board) {

        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                System.out.print(" " + board[i][j] + " ");
            }
            System.out.println("");
        }

        System.out.println("==============================");
    }


}


评论(已关闭)

评论已关闭