回溯算法—解数独

2022-10-13 13:58:39

什么是回溯法?

回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

用回溯算法解决问题的一般步骤:

1、 针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。

2 、确定易于搜索的解空间结构,使得能用回溯法方便地搜索整个解空间 。

3 、以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。

基本思想

从一条路往前走,能进则进,不能进则退回来,换一条路再试。

能解决哪些问题?

  • 排列、组合(子集、幂集、字符全排列)。
  • 二维数组下的DFS搜索(黄金矿工、数独、装载问题、0-1背包问题、旅行售货员问题、八皇后问题、迷宫问题、图的m着色问题)

  • 数组、字符串,给定一个特定的规则,尝试搜索迭代找到某个解。

回溯的解空间

回溯算法有两种常见的解空间模型,分别对应数学中的两种暴力思想,组合以及排列。其中子集问题,对应数学中的组合问题。排列问题对应数学中的排列问题。

解数独

数独,是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复。

数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”

利用回溯算法解数独。思路如下:

1,从0行0列开始,依次往里面填入1-9的数字;


2,然后判断填入这个数字后,该数字对应的行,列和九宫格是否满足不重复的条件;


3,如果当前填入的数字满足,就继续填入下一个数字,下一个数字又从1-9中尝试,如果有满足的数字就说明该数字可用,如果没有,则将该数字又重新置为空格,如此循环往复;


4,如果将所有的数字都尝试了还是没有合适的额,那说明本问题无解,返回false;

/*
 *java 递归
 */
public class ShuduPro {
    private int[][] sudoku;
    public ShuduPro(int[][] sudoku) {
        this.sudoku = sudoku;
    }
    public static void main(String[] args) {
        int[][] sudoku={
                {7, 0, 0, 0, 0, 0, 0, 0, 9},
                {1, 4, 0, 3, 0, 9, 0, 0, 6},
                {0, 0, 0, 0, 0, 0, 5, 1, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 2, 0, 8, 1, 0, 0, 0},
                {0, 0, 9, 0, 2, 0, 8, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 2, 8, 5, 0, 6, 9, 0, 0},
                {0, 0, 0, 1, 0, 0, 3, 0, 2}
        };
        ShuduPro sudu = new ShuduPro(sudoku);
        sudu.backTrace(0,0);
    }
    private void backTrace(int i, int j) {
        //完成,打印数组
        if(i==8 && j==9){
            print_sudoku();
            return;
        }
        //判断是否到列尾,到列尾没到行尾,就换行
        if(j == 9){
            i++;
            j=0;
        }

        //如果是空格就填值
        if (sudoku[i][j] == 0){
            for (int n = 1; n <=9; n++){
                //判断空格中填任一个数是否符合规则
                if(check_repeat(i,j,n)){
                    /*
                     *赋值
                     * 进入下一个空格
                     * 初始化该空格
                     */
                    sudoku[i][j] = n;
                    backTrace(i,j+1);
                    sudoku[i][j]=0;
                }
            }
        }else{
            backTrace(i,j+1);
        }
    }

    /**
     *
     * @param row   行号
     * @param col   列号
     * @param temp   赋的值
     * @return
     */
    private boolean check_repeat(int row, int col, int temp) {
        //判断所在行和列是否有重复数字
        for (int i=0; i < 9; i++){
            if(sudoku[row][i] == temp || sudoku[i][col] == temp){
                return false;
            }
        }
        //判断所在小九宫格中是否有重复
        int tempRow = (row / 3) * 3;
        int tempCol = (col / 3) * 3;
        for (int i = 0; i < 3; i++){
            for (int j = 0; j < 3; j++){
                if(sudoku[tempRow + i][tempCol + j] == temp){
                    return false;
                }
            }
        }
        return true;
    }

    //打印矩阵
    private void print_sudoku() {
        for (int i = 0; i < 9; i++){
            for (int j = 0; j < 9; j++){
                System.out.print(sudoku[i][j]+" ");
            }
            System.out.println(" ");
        }
        System.out.println(" ");
    }

}

数独结果:

  • 作者:臭宝。^
  • 原文链接:https://blog.csdn.net/qq_53125724/article/details/123839061
    更新时间:2022-10-13 13:58:39