求解数独的所有解法,java编程实现

数独是一种考验眼力和逻辑的小游戏,关键在这个“独”字上,横竖不能重复,方块不能重复。今天我给大家介绍一种利用“循环+递归+回溯”的办法来用Java程序替我们完成数独。

先给代码随后讲解:

 1 import java.util.HashMap;
 2 import java.util.Map;
 3
 4 public class T2 {
 5     public static final int N=3;
 6     public static void main(String[] args) {
 7         int x[][]={
 8                 {0,2,0,0,0,9,0,1,0,0},
 9                 {5,0,6,0,0,0,3,0,9,0},
10                 {0,8,0,5,0,2,0,6,0,0},
11                 {0,0,5,0,7,0,1,0,0,0},
12                 {0,0,0,2,0,8,0,0,0,0},
13                 {0,0,4,0,1,0,8,0,0,0},
14                 {0,5,0,8,0,7,0,3,0,0},
15                 {7,0,2,3,0,0,4,0,5,0},
16                 {0,4,0,0,0,0,0,7,0,0},
17         };
18
19         function(x,0,0);
20
21     }
22   
23     private static void function(int[][] x, int r, int c) {
24         if (r>=x.length) {
25             show(x);
26             return;
27         }
28         if (c==0&&(r==x.length/N||r==x.length/N*2||r==x.length)) {
29             if (!checkedbox(x,r)) {
30                 return;
31             };
32
33         }
34         if (c>=x.length) {
35             function(x, r+1, 0);
36             return;
37         }
38
39         if (x[r][c]==0) {
40             for (int i = 1; i <= x.length; i++) {
41                 if (checked(x,r,c,i)) {
42                     x[r][c]=i;
43                     function(x, r, c+1);
44                     x[r][c]=0;
45                 }
46             }
47         }else{
48             function(x, r, c+1);
49         }
50     }
51     private static boolean checkedbox(int[][] x, int r) {
52         for (int k = 0; k < x.length; k+=x.length/N) {
53             Map<Integer, Integer> map=new HashMap<>();
54             for (int i = r-N; i < r; i++) {
55                 for (int j = k; j < k+x.length/N; j++) {
56                     if (map.containsKey(x[i][j])) {
57                         return false;
58                     }
59                     map.put(x[i][j], 1);
60                 }
61             }
62
63         }
64         return true;
65     }
66
67     private static boolean checked(int[][] x, int r, int c, int i) {
68         for (int j = 0; j < x.length; j++) {
69             if (x[j][c]==i) {
70                 return false;
71             }
72             if (x[r][j]==i) {
73                 return false;
74             }
75         }
76         return true;
77     }
78
79     private static void show(int[][] x) {
80         for (int i = 0; i < x.length; i++) {
81             for (int j = 0; j < x.length; j++) {
82                 System.out.print(x[i][j]+" ");
83             }
84             System.out.println();
85         }
86         System.out.println();
87     }
88
89 }

类里有五个函数,一是主函数不多说;二是递归的主体函数function,是解决数独的关键,体现循环+递归+回溯的主要逻辑;三和四都是是一个辨识函数,一些较为复杂的判断逻辑把它抽出来写成辨识函数可以增加代码的可读性;五是一个打印函数很简单。

function函数的实际意义是填写x[r][c]的数字,更确切的说是填写x数组的(r,c)坐标以后的所有数字,内部基本的结构是4个并列的if,第一个if是说如果我填的行号超过了最大值就打印整个数组;第二个if是说当我在填写第3、6、9行开头数字的时候要检查一下上边的三行的方块里是不是有重复的数字;第三个if是说我填写到最后一个元素的时候,要转到下一行开头去;第四个if是说当前的坐标是0的时候才开始循环填写,否则跳过去填写下一个数字。

checkedbox函数利用了一个很巧妙的查重思想----循环嵌套map集合的先查后装思想。当然这个思想你肯定没听说过,因为这个名字是我起的。注意我在第59行给map装值的时候是把数组的值装在map的键里,这样是为了第56行使用map集合的containsKey函数。当然我这样给方块查重是有点秀操作了,其实用一个长度为9的数组也可以。

checked函数和show函数都非常简单,就不多提了。

我给出的数独例子是一个只有一个结果的数独,是比较难的,有兴趣的话可以去搜一搜别的数独来测试一下这个代码吧!!

这个方法可以把一个数独的所有解法全部列举出来

拓展:

  这个循环+递归+回溯的模式可以解决所有按照规则填写数字的问题,比如说:九宫格填写1-9横竖斜相加相等啦、十六宫格填写1-16啦等等。

  

时间: 2024-10-11 12:59:37

求解数独的所有解法,java编程实现的相关文章

Java编程用栈来求解汉诺塔问题的代码实例(非递归)_java - JAVA

文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 [题目] 汉诺塔问题比较经典,这里修改一下游戏规则:现在限制不能从最左侧的塔直接移动到最右侧,也不能从最右侧直接移动到最左侧,而是必须经过中间.求当塔有N层的时候,打印最优移动过程和最优移动总步数. [解答] 上一篇用的是递归的方法解决这个问题,这里我们用栈来模拟汉诺塔的三个塔,也就是不用递归的方法 原理是这样的:修改后的汉诺塔问题不能让任何塔从左直接移动到右,也不能从右直接移动到左,而是要经过中间,也就是说,实际上

[LeetCode] 37. Sudoku Solver 求解数独

Write a program to solve a Sudoku puzzle by filling the empty cells. A sudoku solution must satisfy all of the following rules: Each of the digits 1-9 must occur exactly once in each row. Each of the digits 1-9 must occur exactly once in each column.

求解数独回溯算法

实现的java代码如下: //判断a[i][j]取值val是否有效 public boolean isValid(int[][] a, int i, int j, int val){ //判断是否跟同行冲突 for(int j1=0;j1<9;j1++){ if(a[i][j1]==val) return false; } //判断是否跟同列冲突 for(int i1=0;i1<9;i1++){ if(a[i1][j]==val) return false; } //找出a[i][j]所在的九

西安尚学堂练习09.17|Java编程笔试面试题

下列哪些类型能被throw语句抛出? A. Error B. Exception C. Throwable D. Object [解]注意Error也是可以被throw的,只是通常Error出现程序就中断了,我们并不会去捕获. 2.编程:给定两个字符串A,B(只包含26个英文字母),输出所有公共的最长子字符串(如果出现重复子串,则输出多次) 输入包括两行,每行为一个连续字符串(大小写敏感) 输出包括多行,每行为扫描到的最长公共子串,按照该子串在字符串A(即第一行输入字符串)中出现的先后次序输出

异常笔记--java编程思想

开一个新的系列,主要记一些琐碎的重要的知识点,把书读薄才是目的...特点: 代码少,概念多... 1. 基本概念 异常是在当前环境下无法获得必要的信息来解决这个问题,所以就需要从当前环境跳出,就是抛出异常.抛出异常后发生的几件事: 1.在堆上创建异常对象. 2.当前的执行路径中止                                          3. 当前环境抛出异常对象的引用.                                         4. 异常处理机制接

《Java编程思想》第十三章 字符串

<Java编程思想>读书笔记 1.String作为方法的参数时,会复制一份引用,而该引用所指的对象其实一直待在单一的物理位置,从未动过. 2.显式地创建StringBuilder允许预先为他指定大小.如果知道字符串多长,可以预先指定StringBuilder的大小避免多次重新分配的冲突. 1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月1日 下午4:03:59 4 */ 5 public class UsingStringBuilder {

Java编程练习之输出考试成绩的前三名

在慕课网学习的时候遇到了这样一个Java编程练习题,正好对所学习的Java基础知识检验一下: 请根据所学知识,编写一个Java程序,实现输出考试成绩的前三名 要求: 1考试成绩已保存在数组scores中,数组元素依次为89 , -23 , 64 , 91 , 119 , 52 , 73 2要求通过自定义方法来实现成绩排名并输出操作,将成绩数组作为参数传入 3要求判断成绩的有效性( 0-100 ),如果成绩无效,则忽略此成绩 我自己分析了一下这个程序的过程: (1)首先是定义一个包含整型数组参数的

《Java编程那点事儿》读书笔记(七)——多线程

1.继承Thread类 通过编写新的类继承Thread类可以实现多线程,其中线程的代码必须书写在run方法内部或者在run方法内部进行调用. public class NewThread extends Thread { private int ThreadNum; public NewThread(int ThreadNum){ this.ThreadNum = ThreadNum; } public void run(){ try{ for(int i = 0;i < 10;i ++){ T

Java编程思想【温故知新】

第一章:对象导论 1. 抽象过程(类与对象的关系) 类是一类对象的共同行为(成员函数)与状态(成员变量),对象是具体类的实例化.(Eg.人类是一个类,共同的行为:吃,状态:名字.) [类创建者需要考虑这件事情,回头看看这个概念四个字醍醐灌顶,每次创建这个类的时候,想一想这个类是需要什么成员函数与成员变量来满足单一职责的原则] 2. 每个对象都提供服务:程序设计本身的目标就是去创建能够提供服务来解决问题的一系列对象. 3. 被隐藏的具体实现:类创建者与客户端程序员使用者. 往往来说,每个程序员都是