java数独解法

玩了好久的数独,前几天突发奇想写一个解法,看了好多文章和源码,像回溯法和唯一解法,都不太理解其思路,于是就自己动手写了一个,效率还算可以,有优化的空间,但是懒得优化了。
整体的解法思路就是列出每个空格的备选数,然后逐一尝试,可谓是最笨的解法了,分享给大家图个乐,还希望大佬看到了可以指点一下里面的不足之处。同样因为懒,就没做成web应用,一个main方法自己跑着玩了就。
代码里面包含了1-5级的数独谜题例子(测试用的,就没删除),还有一个从控制台获取谜底的方法。
第一次发文章有些紧张啊,转载的话表明一下出处就行了,废话不多说,上代码

import java.util.*;


public class ShuDuKey {
    static boolean done = false;
    public static void  main(String[] args) throws Exception {
        Integer[][] maps1 = {
                {0,0,0,0,0,0,0,0,3},
                {8,9,7,6,3,4,5,2,1},
                {5,4,0,1,9,0,0,0,0},
                {4,0,0,0,1,5,0,7,0},
                {0,0,0,8,0,6,0,0,0},
                {0,1,0,3,4,0,0,0,2},
                {0,0,0,0,2,3,0,6,4},
                {0,3,5,0,0,7,2,1,8},
                {6,0,0,0,0,0,0,0,0}
        };
        Integer[][] maps2 = {
                {0,1,0,0,0,6,2,0,0},
                {0,0,0,5,3,0,9,0,8},
                {6,9,0,2,4,0,0,0,0},
                {7,0,0,0,0,0,3,9,0},
                {0,3,5,0,6,0,8,4,0},
                {0,8,4,0,0,0,0,0,7},
                {0,0,0,0,5,4,0,3,1},
                {4,0,6,0,8,3,0,0,0},
                {0,0,1,9,0,0,0,0,0}
        };
        Integer[][] maps3 = {
                {4,6,8,0,5,0,0,7,0},
                {5,0,0,9,7,0,0,0,3},
                {0,0,0,0,0,1,0,0,8},
                {0,0,7,0,0,0,0,5,0},
                {0,9,0,0,2,0,0,4,0},
                {0,5,0,0,0,0,8,0,0},
                {6,0,0,2,0,0,0,0,0},
                {2,0,0,0,6,5,0,0,4},
                {9,7,0,0,0,0,2,8,6}
        };
        Integer[][] maps4 = {
                {6,4,0,0,3,8,7,0,9},
                {5,0,8,9,0,0,0,0,0},
                {0,0,0,0,1,0,0,0,0},
                {0,3,0,0,0,0,5,0,0},
                {0,0,0,7,2,1,0,0,0},
                {0,0,9,0,0,0,0,7,0},
                {0,0,0,0,9,0,0,0,0},
                {0,0,0,0,0,6,4,0,3},
                {3,0,1,4,7,0,0,8,5}
        };
        Integer[][] maps5 = {
                {0,0,4,2,0,0,8,0,0},
                {0,0,0,0,0,0,0,0,0},
                {0,9,0,0,0,7,0,3,0},
                {0,0,5,6,8,0,7,0,0},
                {0,3,0,0,1,0,0,9,0},
                {0,0,7,0,5,9,1,0,0},
                {0,2,0,8,0,0,0,7,0},
                {0,0,0,0,0,0,0,0,0},
                {0,0,8,0,0,4,2,0,0}
        };
        Integer[][] mapsMax = {
                {0,0,5,3,0,0,0,0,0},
                {8,0,0,0,0,0,0,2,0},
                {0,7,0,0,1,0,5,0,0},
                {4,0,0,0,0,5,3,0,0},
                {0,1,0,0,7,0,0,0,6},
                {0,0,3,2,0,0,0,8,0},
                {0,6,0,5,0,0,0,0,9},
                {0,0,4,0,0,0,0,3,0},
                {0,0,0,0,0,9,7,0,0}
        };
        Integer[][] sMap = scanMap();
        doShuDu(sMap);
        //doShuDu(maps5);
    }

    //获得数独谜题
    private static Integer[][] scanMap() {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入数独谜题,数字以空格隔开,空白处数字以0代替");
        Integer[][] result = new Integer[9][9];
        for (int i = 0; i < result.length; i++) {
            System.out.println("请输入第"+(i+1)+"行的数字:");
            String[] strArr;
            while (true) {
                String str = sc.nextLine();
                if("exit".equals(str)){
                    System.exit(0);
                }
                strArr = str.split("\\s+|,|,");
                if(strArr.length != 9){
                    System.out.println("输入错误,请重新输入"+(i+1)+"行数字!");
                    continue;
                }
                break;
            }
            for (int j = 0; j < result[i].length; j++) {
                result[i][j] = Integer.parseInt(strArr[j]);
            }
        }
        System.out.println("谜题输入完毕,正在解析中。。。");
        return result;
    }

    //解析数独谜题
    public static void doShuDu(Integer[][] maps){
        long start = System.currentTimeMillis();
        List<String>[][] first = doShuDu1(maps);
        if(done){
            printMap(first);
            System.out.println("共用时:"+(System.currentTimeMillis()-start));
            return;
        }
        System.out.println("执行第二步————————————————————————————————————————》》》");
        List<String>[][] second = doShuDu2(maps,first);
        if(done){
            printMap(second);
            System.out.println("共用时:"+(System.currentTimeMillis()-start));
            return;
        }
        System.out.println("执行第三步————————————————————————————————————————》》》");
    }

    //简单数独谜题解析
    private static List<String>[][] doShuDu1(Integer[][] maps){
        List<String>[][] result = new List[9][9];
        boolean flag = true;
        while(flag){
            done = true;
            flag = false;
            for (int i = 0; i < maps.length; i++) {
                for (int j = 0; j < maps[i].length; j++) {
                    if(maps[i][j] == 0){
                        result[i][j] = getNumList(i,j,maps);
                        if(result[i][j] == null){
                            return null;
                        }
                        if(result[i][j].size() == 1){
                            maps[i][j] = Integer.parseInt(result[i][j].get(0));
                            flag = true;
                        }
                        done = false;
                    }else{
                        if(result[i][j] == null){
                            result[i][j] = new ArrayList<>();
                            result[i][j].add(maps[i][j].toString());
                        }
                    }
                }
            }
        }
        return result;
    }

    //复杂数独谜题解析
    private static List<String>[][] doShuDu2(Integer[][] maps, List<String>[][] first) {
        Map<String,List<String>[][]> resultMap = new HashMap<>();
        Integer[][] tempMaps = arrayCopy(maps);
        List<String>[][] result = new List[first.length][];
        for (int i = 0; i < first.length; i++) {
            result[i] = first[i].clone();
        }
        int[][] count = new int[9][9];
        boolean flag = true;
        while(flag){
            flag = false;
            i:for (int i = 0; i < first.length; i++) {
                for (int j = 0; j < first[i].length; j++) {
                    if(result[i][j].size() > 1){
                        boolean re = true;
                        while(re){
                            re = false;
                            //无法生成符合要求的二维数组,换数字重新来过
                            if(count[i][j] < result[i][j].size()){
                                tempMaps[i][j] = Integer.parseInt(result[i][j].get(count[i][j]++));
                                Integer[][] iarr = arrayCopy(tempMaps);
                                List<String>[][] ls = doShuDu1(iarr);
                                if(ls != null) {
                                    resultMap.put(i+","+j,result);
                                    result = ls;
                                }else{
                                    re = true;
                                }
                            }else {
                                //该位置的数组应用完毕,仍未得到可用解,则置零
                                count[i][j] = 0;
                                //找到上一个选择的数字的位置
                                for (int k = 0; k < count.length; k++) {
                                    for (int l = 0; l < count[k].length; l++) {
                                        if(count[k][l] > 0){
                                            i = k;
                                            j = l;
                                        }
                                    }
                                }
                                result = resultMap.get(i+","+j);
                                for (int k = i; k < 9; k++) {
                                    for (int l = 0; l < 9; l++) {
                                        if(k == i && l == 0){
                                            l = j;
                                        }
                                        tempMaps[k][l] = maps[k][l];
                                    }
                                }
                                j--;
                                break;
                            }

                        }
                        flag = true;
                    }else{
                        tempMaps[i][j] = Integer.parseInt(result[i][j].get(0));
                    }
                }
            }
        }
        return result;
    }

    //获取该位置的候选数字
    private static List<String> getNumList(int i, int j, Integer[][] maps) {
        List<String> temp = getList();
        for (int jj = 0; jj < maps[i].length; jj++) {
            //移除当前同行已经出现的数字
            temp.remove(maps[i][jj]+"");
        }
        for (int ii = 0; ii < maps.length; ii++) {
            //移除当前同列已经出现的数字
            temp.remove(maps[ii][j]+"");
        }
        //移除九宫格已经确定的数字
        int d = i/3*3;
        int h = j/3*3;
        for (int k = d; k < d+3; k++) {
            for (int l = h; l < h+3; l++) {
                temp.remove(maps[k][l]+"");
            }
        }
        if(temp.size() > 0){
            return temp;
        }
        return null;
    }

    //获取1-9的集合
    private static List<String> getList(){
        List<String> result = new ArrayList<>();
        for (int i = 1; i < 10; i++) {
            result.add(i+"");
        }
        return result;
    }

    //复制二维数组
    private static Integer[][] arrayCopy(Integer[][] oo){
        Integer[][] result = new Integer[oo.length][];
        for (int i = 0; i < oo.length; i++) {
            result[i] = oo[i].clone();
        }
        return result;
    }

    //打印二维数组
    public static void printMap(Object[][] map){
        for (int i = 0; i < 9; i++) {
            if(i%3==0 && i!=0){
                System.out.println("---------------------");
            }
            for (int j = 0; j < 9; j++) {
                if (j==8) {
                    System.out.println(map[i][j]);
                } else if(j == 2 || j == 5) {
                    System.out.print(map[i][j]+" | ");
                }else{
                    System.out.print(map[i][j]+" ");
                }
            }
        }
    }

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值