数独问题

一、问题简介

你一定听说过“数独”游戏。
如【图1.png】,玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个同色九宫内的数字均含1-9,不重复。
数独的答案都是唯一的,所以,多个解也称为无解。
本图的数字据说是芬兰数学家花了3个月的时间设计出来的较难的题目。但对会使用计算机编程的你来说,恐怕易如反掌了。
本题的要求就是输入数独题目,程序输出数独的唯一解。我们保证所有已知数据的格式都是合法的,并且题目有唯一的解。
格式要求,输入9行,每行9个字符,0代表未知,其它数字为已知。
输出9行,每行9个数字表示数独的解。

例如:
输入(即图中题目):
005300000
800000020
070010500
400005300
010070006
003200080
060500009
004000030
000009700

程序应该输出:
145327698
839654127
672918543
496185372
218473956
753296481
367542819
984761235
521839764

这里写图片描述

二、思路分析

题目中有四个筛选条件即
1、每行不能含有重复的数字
2、每列不能含有重复的数字
3、每个小的九宫格不能有重复的数字。
4、每个格子的值在1-9之间

为此先创建四个二维数组
1、s数组用于存储刚开始时从控制台出入的矩阵
2、rol[i][x]==1代表第i行已存在数字x,那么rol[i][x]==0代表第i行不存在数字x
3、col[j][x]==1代表第j行已存在数字x,那么col[j][x]==0代表第j行不存在数字x
4、small[j/3+i/3*3][x]=1代表第(j/3+i/3*3)个九宫格(从左到右,从上到下)已存在数字x,small[j/3+i/3*3][x]=0代表第(j/3+i/3*3)个九宫格(从左到右,从上到下)不已存在数字x
(PS:j/3+i/3*3是为了判断i行,j列是属于哪个九宫格,找几个位置代入就知道为何如此写。)

创建这些数组是为了在向s数组的某位置插入数字时,根据另外三个数组来判断是否可以在此位置插入该数字,
因此在对s数组进行初始化,即接受控制台上的矩阵时,就要对另外三个数组进行初始化,它们起标志作用。

从棋盘的左上角开始,判断此处是否可以插入数字,如果可以就插入一个数字,然后跳到下一列,如果到了最后一列,便跳到下一行,每到一个位置便插入一个数字,如果该数字不满足条件,便换一个数字,然后向下,若所有数字都试过了还不行,便回退到上一个位置,更换上一个位置的数字,然后再向下运行,如此反复,最终只有是满足条件的数字才能走到最后,也就是说走到最后的便是正确答案。

三、解决代码

public class Demo6 {
    static int s[][] = new int[9][9];
    static int rol[][] = new int[9][10];
    static int col[][] = new int[9][10];
    static int small[][] = new int[9][10];

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String[] line = new String[9];
        for (int i = 0; i < 9; i++) {
            line[i] = scanner.nextLine();
        }
        char[][] c = new char[9][9];
        for (int i = 0; i < 9; i++) {
            c[i] = line[i].toCharArray();
        }
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                s[i][j] = Integer.parseInt(c[i][j] + "");
                if (s[i][j] != 0) {//在接受控制台上的矩阵时,就对另外三个数组进行初始化
                    rol[i][s[i][j]] = 1;
                    col[j][s[i][j]] = 1;
                    small[j / 3 + i / 3 * 3][s[i][j]] = 1;
                }
            }
        }
        getResult(0, 0);//从0行0列开始
    }

    public static void getResult(int rolIndex, int colIndex) {
        if (rolIndex == 9 && colIndex == 0) {//找到答案
            // 输出答案
            for (int i = 0; i < 9; i++) {
                for (int j = 0; j < 9; j++) {
                    System.out.print(s[i][j]);
                }
                System.out.println();
            }
        }
        if (rolIndex < 9) {//未找到答案
            if (s[rolIndex][colIndex] != 0) {
                if (colIndex == 8) {// 到最后一列,另起一行
                    getResult(rolIndex + 1, 0);
                } else {// 到下一列
                    getResult(rolIndex, colIndex + 1);
                }
            } else {
                for (int x = 1; x <= 9; x++) {
                    //筛选条件
                    if (col[colIndex][x] != 0 || rol[rolIndex][x] != 0
                            || small[colIndex / 3 + rolIndex / 3 * 3][x] != 0) {
                        continue;//说明不能插入当前数x,结束本次循环
                    }
                    s[rolIndex][colIndex] = x;
                    rol[rolIndex][x] = 1;
                    col[colIndex][x] = 1;
                    small[colIndex / 3 + rolIndex / 3 * 3][x] = 1;
                    if (colIndex == 8) {
                        getResult(rolIndex + 1, 0);//进入下一行
                    } else {
                        getResult(rolIndex, colIndex + 1);//进入下一列
                    }

                    //----------------------------------------
                    //到这一步说明这个x不能满足需要,back
                    s[rolIndex][colIndex] = 0;
                    rol[rolIndex][x] = 0;
                    col[colIndex][x] = 0;//前面进行了赋值,这里撤回
                    small[colIndex / 3 + rolIndex / 3 * 3][x] = 0;
                }
            }
        }

    }

}

Rome is not built in a day.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值