在生成数独题目时,流程是:生成一个完整的数独——随机挖空——解题——如果只有一个解,则生成该题目,如果有多个解,则重新挖空。

数独题目的生成涉及的一个算法是回溯法,这里面的完整数独的生成、求解都用到了回溯法。

1. 生成完整数独

在生成部分,先生成所有宫的1,再生成所有宫的2,以此类推。

主要有三个值:

boolean[][][] placeable = new boolean[9][9][9];// 第几个数字,第几宫,第几号位置

int[][] stepPos = new int[9][9];// 第几个数字,第几宫,值是位置

int[][] result=new int[9][9];

placeable 用来存储每个数字在每个宫的每个位置是否可以放置,初始时,只要该位置没有被占就可以放置,在生成数独的过程中,尝试在这个位置放置某数,如果与行列宫有冲突,则需更新placeable 。

stepPos 用来存储某个宫中已经放置的数字的位置。

result既是存储生成的数独。

生成阶段的回溯是通过一个双重循环实现的:

private static int[][] tryGenerateFinalAnswer() {int[][] result=new int[9][9];for (int number = 0; number < 9; number++) {//注意这里没有gong++for (int gong = 0; gong < 9;) {ArrayList<Integer> PlaceableList = getPlaceableList(number, gong);int length = PlaceableList.size();//回溯算法的重点就是这里,如果当前一步走不下去,就返回上一步,重走if (length <= 0) {                    resetPlaceable(result,number, gong);gong--;if (gong < 0) {number--;gong = 8;}removeNum(result, number, gong);}else {int pos = PlaceableList.get(random.nextInt(length));if (isCollide(result,number, gong, pos)) {placeable[number][gong][pos] = false;}else {addNum(result, number, gong, pos);gong++;}}}}return result;}

其实一开始写数独生成的时候,想的是先随机生成第一个宫的所有数字,第二个宫在不与第一个宫冲突的情况下生成所有数字,以此类推,就是以宫为主顺序生成数独。这样的做法理论上可行,但实际上需要非常大量的运算,而且极易容易冲突。因为后面一旦走不下去,往往要返回一个宫的所有数字,但是以数字为主顺序,走不下去就只需要返回一个宫的一个数字。

2. 随机挖空

随机挖空的部分比较简单,但是要注意使用另一个二维数组来存储生成的题目,不要在完整的数组上动,因为后面解题部分要对比完整的数组,看看解题是否正确。

3. 解题

解题部分时参考了另一位大佬的代码,之前看的时候距今已经过了一年有余,所以找不到他的博客了。

解题部分的思想非常的巧妙,首先将数独题目中1-9这9个数,转化成二进制中1的位置。000000100表示3,如001000000表示7,而题目中空缺的位置,则以111111111表示,这表示这个位置的候选数字是1~9。

然后根据已确定的数字分析更新空格的候选数字,比如候选值有2、3、6,则该空的二进制数就是000100110。当二进制中只有一个1,则表示该值可以确定,使用Integer.bitCount(data[m][i]) 方法判断二进制中有几个1。

这里的分析主要就是排除行列宫中已有的数字。

一直循环分析所有空格,直到不能从已确定的数字中分析出新的候选信息,就从一个空格的候选值中假设一个值填进格子中,再以此推测剩余的空格,直到所有格子都被填满,或者是填补下去,那么就返回之前的假设,填其他值,以此类推。这其实和我们正常解数独的思路是一样的。

如果题目已经求得两个解,则返回,重新生成题目。因为这个题目是从一个完整的数独挖空而来,所以不可能没有解。

解题的回溯部分主要通过递归实现:

  private static void solve(int[][] data) {if(resultNum>1) {return;}analyse(data);int result = check(data);if (result == 1) {int[] position = findLessCandidatesPos(data);int pv = data[position[0]][position[1]];int pvcount = Integer.bitCount(pv);for (int i = 0; i < pvcount; i++) {int testV = 1 << ((int) (Math.log(Integer.highestOneBit(pv)) / Math.log(2)));pv ^= testV;int[][] copy = copyArray(data);copy[position[0]][position[1]] = testV;//这里不理解为什么要返回if(i>1) {return;}solve(copy);}           }else if (result == 0) {resultNum++;System.out.println("------------------------------------第"+(resultNum)+"个答案---------------------"+ (System.nanoTime() - startTime) / 1000000.0 + "ms---");answer=data;binaryToInt(answer);printByRow(answer);}}

解题中值得借鉴的就是将数字1~9表示成二进制中1的位置,这样可以很好的表示候选值。除了数独中的数字与候选值表示成二进制中1的位置,

在找候选值的方法中,也是用三个二进制数分别表示当前值所在的行、列、宫已经存在的数字,来计算候选值的。

在判断是否冲突的方法,也是用三个二进制数分别表示当前值所在的行、列、宫已经存在的数字,来判断是否冲突的。

唯一解的数独题目生成器代码://download.csdn.net/download/Michaelia_hu/12013857

唯一解的数独题目生成器——理解回溯法相关推荐

  1. 基于C语言的9*9数独生成器(回溯法)

    基于C语言的9*9数独生成器 题目要求如下图所示: 我们采用的思路是首先生成一个完整的9*9数独,然后再随机挖空,这样就形成了一个数独局面. 代码如下: #include <stdio.h> ...

  2. 回溯法简单应用--解数独

    简单介绍 数独是当下较为流行的数学游戏之一.通常数独由9x9的格子构成,其中将9x9的格子分为9个3x3的区域,称为"宫"(通常宫与宫之间会用较粗的线来分隔).游戏的目标则是在格子 ...

  3. 回溯法求解数独问题(最简单,通俗易懂,附C++代码)

    问题描述:数独是一种运用纸.笔进行演算的逻辑游戏.玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行.每一列.每一个九宫格内的数字均含1-9,不重复 要求:设计算法随机生成不同 ...

  4. 彻底搞懂回溯法(本文真的很详细)

    目录 回溯法理论基础 组合问题 组合问题 组合总和 组合总和(一) 组合总和(二) 组合总和(三)(本题去重特别重要) 多个集合求组合 切割问题 子集问题 子集问题(一) 子集问题(二) 递增子序列 ...

  5. c语言实现全排列并存储,C语言实现全排列和回溯法总结

    一.递归实现全排列 #include"cstdio" int A[]; void print_permutation(int n,int *A,int cur){ if(cur== ...

  6. LV算法和回溯法结合解n后问题

    我的算法作业:n=12 ~ 20时,求出较优的stopVegas值.(也就随机放置几个皇后比较好的问题). 解答:(VC6.0下调试通过,可能某些统计数据的计算部分,有不太妥当的地方,贴出来也就是有高 ...

  7. LeetCode 例题精讲 | 08 排列组合问题:回溯法的候选集合

    点击关注上方"五分钟学算法", 设为"置顶或星标",第一时间送达干货. 转自面向大象编程 本期例题:LeetCode 46 - Permutations[1]( ...

  8. 五大经典算法之回溯法及其应用

    前言 回溯法是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的 ...

  9. 回溯法专题--回溯法总结

    文章目录 前言 看到题目有 "所有" 两个字,先看看回溯法能不能解决 一.问题一: 二.解决主要问题 三.回溯法模板 前言 回溯法 - - 本质就是利用递归算法 是纯暴力搜索 - ...

  10. 算法分析与设计——回溯法实验报告

       算法导论  课程设计 成 绩 题    目:    回 溯 法 学院班级:        1613013         学    号:      16130130216       姓     ...

最新文章

  1. 中农植保-昆虫进化与基因组诚聘博后及科研助理-三亚中国农业大学研究院
  2. 搭建Cocos Code IDE开发环境
  3. Linux vim使用心得--一些高级话题
  4. 18.phpmyadmin 4.8.1 远程文件包含漏洞(CVE-2018-12613)
  5. Autofac实现有条件的DI
  6. 【牛客 - 157E】青蛙(floyd最短路,建图)
  7. 京东到家程序员删库跑路 ! 讲一讲 MySQL 数据备份杀手锏 binlog
  8. oracle新建一个用户_Kettle 连接oracle将数据保存到Excel
  9. github ssh 配置_搭建自己的技术博客系列 2:把 Hexo 博客部署到 GitHub 上
  10. 用Lucene[1].net对数据库建立索引及搜索+
  11. (凭什么断点要放入堆栈?)微机学习:第八课
  12. 啊哈算法—解救小哈(深度优先搜索)
  13. 项目建议书模板doc_简历模板大全,直接可以下载使用的简历模板
  14. 2018第九届蓝桥杯C++省赛B组题目汇总
  15. PKI加密体系加密过程及原理
  16. java oop 题目_JavaOOP试题JavaOOP试题.doc
  17. 【Tensorflow 报错】struct.error: 'i' format requires -2147483648 = number = 2147483647
  18. 浏览器全屏相关常用代码
  19. vue3 Extraneous non-props attributes (modelValue) were passed to component but could not be automati
  20. CSS3实现扇形动画菜单特效

热门文章

  1. [乐意黎原创]联想G470老笔记本升级改造
  2. OGRE实现纸娃娃系统
  3. opencv同态滤波
  4. SAS基础-日期时间本质
  5. idea git提交代码步骤
  6. 计算几何模板(kuangbin)
  7. Servlet面试题整理
  8. 学了CPDA数据分析师认证课程对工作有什么好处?
  9. Oracle 数据库sql语句修改表字段的字段类型和长度
  10. endnotex8使用教程_EndNote X8初级教程(原创)