数独问题(Java版)

Posted ZSYL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数独问题(Java版)相关的知识,希望对你有一定的参考价值。

题目描述

玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列 均含1-9,不重复。
数独的答案都是唯一的,所以,多个解也称为无解。

本题的要求就是输入数独题目,程序输出数独的唯一解。我们保证所有已知数据的格式都是合法的,并且题目有唯一的解。

格式要求:
输入9行,每行9个字符,0代表未知,其它数字为已知。
输出9行,每行9个数字表示数独的解。

代码展示

import java.util.Scanner;

public class Main {
    static int[][] matrix;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        matrix = new int[9][9];
        // 初始化矩阵,0:代表空位
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                matrix[i][j] = sc.nextInt();
            }
        }
        System.out.println("------------------");
        dfs(0, 0);
    }
    // 深度遍历,一行一行开始
    public static void dfs(int i, int j) {
        // 递归结束,到第10行
        if (i == 9) {
            printResult();
            System.exit(0);  // 程序结束,否则一直打印结果,因为递归深度太深
        }
        // 如果当前 i行 j列 是 0即空位置,则将 1-10分别试着放入空位,假如放入,判断第i行第j列是否存在该数字
        if (matrix[i][j] == 0) {
            for (int k = 1; k < 10; k++) {
                // 如果不存在,则将该数字放入,从该行下一列开始,继续试着填充
                // i+(j+1)/9, (j+1)%9 巧妙的实现,遍历一行,遍历完了换到下一行
                if (!check(i, j, k)) {
                    // 如果将当前位置i,j 先初步设置为了 k,试着往下继续递归填数
                    // 可能遇到某一个位置,不能继续填数了,因为行列有重复,无法填值成功,则当前栈中方法逐步出栈,直到回溯错误的填数位置
                    matrix[i][j] = k;
                    dfs(i+(j+1)/9, (j+1)%9);
                }
            }
            // 回溯过程中需要,复位
            matrix[i][j] = 0;
        } else {
            dfs(i+(j+1)/9, (j+1)%9);
        }

    }
    // 检查 i行 j列 是否已存在 num
    public static boolean check(int i, int j, int num) {
        for (int k = 0; k < 9; k++) {
            if (matrix[i][k] == num || matrix[k][j] == num) {
                return true;
            }
        }
        return false;
    }
    // 输出结果
    public static void printResult() {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                System.out.print(matrix[i][j]+" ");
            }
            System.out.println();
        }
    }
}

输入:

0 0 8 0 7 0 6 0 0
0 1 0 5 6 0 0 0 0
0 2 0 0 0 0 0 0 1
0 6 0 0 0 0 0 0 0
5 7 1 0 3 0 4 9 8
0 0 0 0 0 0 0 7 0
4 0 0 0 0 0 0 6 0
0 0 0 0 4 3 0 5 0
0 0 3 0 5 0 2 0 0


输出

1 3 8 2 7 5 6 4 9
2 1 4 5 6 7 9 8 3
6 2 5 4 8 9 7 3 1
3 6 7 1 9 4 8 2 5
5 7 1 6 3 2 4 9 8
8 4 9 3 2 1 5 7 6
4 5 2 9 1 8 3 6 7
7 9 6 8 4 3 1 5 2
9 8 3 7 5 6 2 1 4

拓展问题

问题描述

给定数列 a,判断是否可以从中选出若干个数,使他们的和恰好为 k。

例如:
输入:
n=4
a={1,2,4,7}
k=13
输出:
Yes

分析:

由于数列中每个数存在加或者不加两种状态,那么可绘制二叉状态树如下:

在这里插入图片描述

因此考虑使用递归算法求解。

代码展示:

import java.util.Scanner;

public class _23_数独问题2 {
    static int[] a;
    static int k;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        k = sc.nextInt();
        a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
        }
        if (dfs(0, k))
            System.out.println("Yes");
        else
            System.out.println("No");
    }
    // 深度遍历
    public static boolean dfs(int i, int curSum) {
        // 递归结束条件
        if (i+1 == a.length) {
            return curSum + a[i] == k;
        }
        // 剪枝,减少不必要的递归,优化效率
        // 如果当前未到数组末尾,但是已经满足sum==k || sum > k,直接跳出,返回相应结果
        if (curSum >= k) {
            return curSum == k;
        }
        // 对于当前 数可以选择也可以放弃
        // 选择走二叉树左分支
        if (dfs(i+1, curSum+a[i]))
            return true;

        // 不选择走有分支
        if (dfs(i+1, curSum))
            return true;
        // 若左右分支都不满足,则回溯时返回 false
        return false;
    }
}

参考博客 Link

感谢

以上是关于数独问题(Java版)的主要内容,如果未能解决你的问题,请参考以下文章

为啥我使用回溯解决数独的 JAVA 代码没有给出任何解决方案? [关闭]

java刷题--36有效的数独

java刷题--36有效的数独

java刷题--36有效的数独

Java问题中的蛮力数独求解器算法

用java做一个数独游戏,有现成代码,只需弄一下文字的东西就可以啦,不用太复杂,普普通通的就行.