数独(这个要学习学习)


思路

  1. 要建立几个数组:存测试样例,存横、竖、3*3宫格,存1-9的bool等
  2. 最上方的行i=0,最左边的列j=0
  3. 从上到下,从左到右,一次检查一个格子,先求出这个格子还剩什么数字可以填,然后检查横、竖、33宫格是否都满足?如果是,就检查33宫格的其他两行是否都满足,“都满足就填数(这里是有问题①的)”,不是就换一个数,从头再来。
  4. 最后检查9*9宫格是否都满足。

①:这种情况遇到同一行有多个格子满足的情况是可能会填错数。
——解决方法参考:换一个数,或往下一个格子/下一行填(那就要有9行重复填的行为了相当于会的就填,不会的不填,然后倒回来,之前不会填的就能填了)

参考的答案用到了dfs和hashset来保证数字不重复。
没有代码,没时间写了。

以下代码为牛客用户所写,他的主页:
VagrantYang的牛客主页

此代码链接


import java.util.*;

/**
 * 华为03-数独
 *
 * 此题思路就是dfs,假定空白处为某值,然后依据这个条件纵向求解
 * 若不满足,则回溯,改变该值,继续纵向,找到结果后
 * 用一个变量告诉后面的回溯的过程,使其结束递归,即剪枝
 *
 * 注意一点是:即使该点不为空,也要继续递归考察下一个节点
 * 我就是忘了这一步,调试了好大会,55555
 *
 * 索引的增长:
 * 1.可以使用x,y来保存,y每一步都要加1,而x根据y是否走到末尾来决定是否换行
 * 2.可以使用一个变量index来保存,index / 9 即行数,index % 则列数
 * Create by Special on 2018/3/2 13:38
 */
public class Main {
    static int[][] nums = new int[9][9];
    static boolean isOk;

    private static boolean isValid(int x, int y){
        for(int i = 0; i < 9; i++){
            if(i != y){
                if(nums[x][i] == nums[x][y]){
                    return false;
                }
            }
            if(i != x){
                if(nums[i][y] == nums[x][y]){
                    return false;
                }
            }
        }
        /**
         * 通过以下可以找到x,y所处的9宫格的第一个节点的行列索引
         */
        int row = (x / 3) * 3;
        int col = (y / 3) * 3;
        for(int i = row; i < row + 3; i++){
            for(int j = col; j < col + 3; j++){
                if(i != x && j != y){
                    if(nums[i][j] == nums[x][y]){
                        return false;
                    }
                }
            }
        }
        return true;
    }

    public static void dfs(int x, int y) {
        if(x == 9 && y == 0){
            isOk = true;
            return;
        }
        int tempY = y + 1, tempX = x;
        if(tempY == 9){
            tempY = 0;
            tempX += 1;
        }
        if(nums[x][y] != 0){
            dfs(tempX, tempY);
        }else {
            for(int i = 1; i <= 9; i++) {
                nums[x][y] = i;
                if(isValid(x, y)){
                    dfs(tempX, tempY);
                    if(isOk){
                        return;
                    }
                }
                nums[x][y] = 0;
            }
        }
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        while(input.hasNext()){
            isOk = false;
            for(int i = 0; i < 9; i++){
                for(int j = 0; j < 9; j++){
                    nums[i][j] = input.nextInt();
                }
            }
            dfs(0,0);
            /**
             * 因为数独不唯一,所以为了AC,只能如此,打印出测试用例的特例
             */
//            if(nums[6][0]==2&&nums[6][1]==1&&nums[6][2]==3)
            {
                nums[6][2]=5;nums[6][3]=8;nums[6][4]=4;nums[6][5]=6;nums[6][6]=9;nums[6][7]=7;nums[6][8]=3;
                nums[7][0]=9;nums[7][1]=6;nums[7][2]=3;nums[7][3]=7;nums[7][4]=2;nums[7][5]=1;nums[7][6]=5;nums[7][7]=4;nums[7][8]=8;
                nums[8][0]=8;nums[8][1]=7;nums[8][2]=4;nums[8][3]=3;nums[8][4]=5;nums[8][5]=9;nums[8][6]=1;nums[8][7]=2;nums[8][8]=6;
            }
            for(int i = 0; i < 9; i++){
                for(int j = 0; j < 9; j++){
                    System.out.print((j == 0 ? "" : " ") + nums[i][j]);
                }
                System.out.println();
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值