目录

1. 问题描述

2. 回溯法详情了解地址:

3. 算法设计思路

4.伪码:

5.源代码实现:

6.运行结果

7.时间复杂度分析:

8.与类似问题区别

1. 问题描述

     九宫格是在81个格子(9×9)中,要满足以下条件(1) 每个横行和竖列中的9个格子都包含数字19不重复;(2) 每个黑色粗实线围住的9个格子(3×3)都包含数字19不重复。如图所示: 

java 打印九宫格算法 java九宫格游戏_九宫格

要求找出给定数字的九宫格。

输入输入9行9列81个数字,其中0表示要填的数字。

输出输出满足条件的九宫格。

测试样例如下:

  

  

0 6 1 0 3 0 0 2 0

0 5 0 0 0 8 1 0 7

0 0 0 0 0 7 0 3 4

0 0 9 0 0 6 0 7 8

0 0 3 2 0 9 5 0 0

5 7 0 3 0 0 9 0 0

1 9 0 7 0 0 0 0 0

8 0 2 4 0 0 0 6 0

0 4 0 0 1 0 2 5 0

7 6 1 9 3 4 8 2 5

3 5 4 6 2 8 1 9 7

9 2 8 1 5 7 6 3 4

2 1 9 5 4 6 3 7 8

4 8 3 2 7 9 5 1 6

5 7 6 3 8 1 9 4 2

1 9 5 7 6 2 4 8 3

8 3 2 4 9 5 7 6 1

6 4 7 8 1 3 2 5 9

 

2. 回溯法详情了解地址:

五大常用算法之回溯法详解

3. 算法设计思路

解空间树:九分支子集树,解向量用二维数组9*9矩阵表示。

可行性约束条件1:matrix[i][j]==0;

由于行列数字及小九宫格内数字不相同,因此对于给定数字num,约束条件2:matrix[i][j]!=num。

限界函数:不涉及最优值,因此不许考虑。

实例分析:

对于3*3数独问题:

对每一个空格开始从1至9遍历,在满足约束函数的条件下,进行填数。若不满足,则擦除当前已填空格,另寻路径。

函数解释:

backtrack:行列数下标都从0开始。当i(行)==8,j(列)==9时,算法搜索至叶结点,得到满足正确解的数独,算法调用printSudoku打印正确的数独解。当i<8&&j<9时,以深度优先搜索对相应子树遍历t:1 to 9,若不满足约束,则剪去相应的子树。

judge:判断约束条件是否满足,满足则返回true

printSudoku:打印数独

4.伪码:

backtrack算法:

S1:if matrix[i][j]==0 //当前位置为空
S2:then for(t=19)    //遍历1~9
S3:    if(judge(i,j,t))   //满足约束条件
S4:      matrix[i][j] = t;  
S5:      backtrcak(i,j+1);
S6:      matrix[i][j] = 0;
S7:else then
S8:    backtrack(i,j+1)

judge算法:

S1:for(i=08)
S2:   if matrix[row][i]==num  || matrix[i][line]==num //大九宫格数字重复
S3:     return false
S4:for(i=03) 
S5:   for(j=03)
S6:      if matrix[smallRow*3+i][smallLine*3+j]==num //小九宫格数字重复
S7:         return false
S8:return true


5.源代码实现:

public class Sudoku {
    //完全n叉树,9分支,每层每一结点都要遍历九个子节点
    //每一层代表一个格子,每个格子共有九种选择,遍历1-9找到满意条件的数字
    int[][] matrix = {//九宫格行列数为0-8
            {0, 6, 1, 0, 3, 0, 0, 2, 0},
            {0, 5, 0, 0, 0, 8, 1, 0, 7},
            {0, 0, 0, 0, 0, 7, 0, 3, 4},
            {0, 0, 9, 0, 0, 6, 0, 7, 8},
            {0, 0, 3, 2, 0, 9, 5, 0, 0},
            {5, 7, 0, 3, 0, 0, 9, 0, 0},
            {1, 9, 0, 7, 0, 0, 0, 0, 0},
            {8, 0, 2, 4, 0, 0, 0, 6, 0},
            {0, 4, 0, 0, 1, 0, 2, 5, 0}};

    void backtrack(int i, int j) {//81层结点通过9*9二维数组表示
        if(i==8&&j==9){ //遍历至第81层,8行8列时遍历结束(九宫格行列数为0-8)
            //得到数独正确解答,程序结束
            printSudoku(); //打印数组
        }
        if(j==9){//换行
            i++;
            j=0;
        }
        if (matrix[i][j] == 0) {//判断九宫格i行j列是否为空
            for (int t = 1; t <= 9; t++) { //若该位置为空,则遍历1-9,判断数字是否满足条件
                if (judge(i, j, t)) {
                    matrix[i][j] = t; //将符合条件的数字填入空格
                    backtrack(i, j + 1); //回溯下一层,即进入下一个空格
                    matrix[i][j] = 0; //初始化数独矩阵,恢复现场,向上回溯还原结点状态
                }
            }
        } else {
            backtrack(i, j + 1);
        }
    }

    boolean judge(int row, int line, int num) { //行、列、数字
        for (int i = 0; i < 9; i++)  //判断该行该列是否有重复数字
            if ((matrix[row][i] == num) || (matrix[i][line] == num))
                return false;
        //判断小九宫格是否有重复数字
        int smallRow = row/3;//找到小九宫格起始行列
        int smallLine = line/3;
        for(int i=0;i<3;i++){//遍历小九宫格,比较数字
            for(int j=0;j<3;j++){
                if(matrix[smallRow*3+i][smallLine*3+j]==num)
                    return false;
            }
        }
        return true;
    }

    void printSudoku(){//打印数独
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Sudoku s = new Sudoku();
        s.backtrack(0, 0);
    }
}

6.运行结果

 

java 打印九宫格算法 java九宫格游戏_intellij idea_02

7.时间复杂度分析:

算法从根结点出发,搜索了81层子树,每一层的每一结点都是九分支。不断地遍历有点类似穷举法,因此算法量非常大,效率慢。(9*9数独排列组合数量非常巨大)

结点共有java 打印九宫格算法 java九宫格游戏_intellij idea_03,时间复杂度为java 打印九宫格算法 java九宫格游戏_intellij idea_04

8.与类似问题区别

与n后问题比较,同样地,都是通过完全n叉树解决问题。数独填数游戏在九宫格每一格进行搜索,在约束函数条件下找到解,若找不到则向上回溯。而皇后也是在约束条件下找正确位置,在当前正确解的情况下继续搜索,若出错则向上回溯。容器比较,九宫格可以看作9*9二维数组进行搜索,而n后问题层数与所找位置一致,只需要一维数组记录。

与图的m着色问题比较,二者解空间都为高度为n+1的完全m叉树,解空间树第i层中每个节点都有m个儿子,每个儿子对应于x[]可能的着色之一(填数),第n+1层结点均为叶结点。