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

要求:设计算法随机生成不同难度的数独游戏,阐述如何评价所生成数独的难度。

数独简介:数独(Sudoku)是一种当前非常流行的填数游戏,但与数字的运算毫无关系,主要考察人们的逻辑推理能力和观察能力。数独起源于拉丁方阵,由单元格(Cell)、行(Row)、列(Column)、宫(Box、Block)等元素组成,规则是在每行、每列、每宫的九个单元格中填入数字1-9,不重复。给定一定数量提示数的盘面作为初始条件,称为初盘。根据规则将所有单元格填满得到的盘面称为终盘,也就是数独的解。标准的数独初盘只能对应一个终盘。

设计思路:

对于数独程序,主要需要解决两个问题:数独生成、数独求解。目前影响比较大,功能比较完善的数独程序有:Hodoku、Sudoku Explainer。

要实现数独的生成,就要先理清每一个位置的约束条件,经我们小组讨论发现,每个位置的数需要满足四个约束条件:

首先,这个格子里不能有数字,即为空

其次,同一行不能有相同数字

再次,同一列不能有相同数字

最后,同一个九宫格不能有相同数字

用算法的形式把这四个约束条件表现出来,就是数独的生成。

采用随机方式生成数独,即从空白的数独盘面开始随机填数,填入的数字不能违背数独的基本规则,并且要保证解的唯一性。在随机填入过程中,判断某个位置是否可以填入一个随机的数是根据这一位置所处行列宫区域中是否已有此数来决定。当填入这一数之后,修改它所处区域的标记信息。当生成一个完整的数独时,在按照下标随机将数独里面的数进行置零操作,就生成了一个数独的问题,然后再进行数独求解,发现是多解数独时,随机选取两个解,在他们的差异位置处随机选择一个填入,再进行求解,这样可以快速定位到当前搜索路径的某个有效分枝,这样反复进行,可根据当前搜索路径,快速定位到最后一个分枝,找到解是唯一的初盘。

计算机程序求解数独,一般采用回溯法,对于任意数独初盘,好的算法都可以在一秒内得到解。目前,非常有效的算法,是舞蹈链(Dancing Links)算法。它实际上也是一种回溯算法,巧妙地运用了双向十字链表的数据结构,用空间换取时间,将数独求解转化为一个精确覆盖问题,用C语言实现的算法,在普通的微机上,能够在0.1ms左右对任意标准数独进行求解。

算法设计:

数独求解:

首先,要先确定该数独中空格的数量以及位置,用count记录空格的数量即所需填的数量,用blank数组记录所有需要填的空格的坐标。

   int count = 0;   //count用于记录需要填的空格数量,初始为0int blank[81][2];    //blank数组用于记录所有需要填的空格的坐标           for(int i = 0;i < 9;i++)                     for(int j = 0;j < 9;j++)                  if(sd[i][j] == 0)                        {                                             //     将整个数独扫描一遍,blank[count][0]=i;                  blank[count][1]=j;               count++;                           //统计其中的空格数量}

然后根据blank数组记录的sd数组里面空格的下标位置来进行试填,试填时要满足同行、同列以及同块不出现相同的数字,利用一个循环,将sd里面原来的空格里面的数字先进行加一然后进行循环,如果满足了条件,就将该数字填入sd数组里面,作为改下标的一个解,并且将top加一。但是因为第一次填数的时候不一定就是正确的数,所以当出现错误是,就会运用top进行回溯到上一步的操作。直到完全将整个数独游戏解决。但是如果数独问题没有正确的答案的话,top会小于0,最后输出“您的数独问题有错误,请输入正确的数度问题。”

        int a = blank[top][0];        //如果执行到这里,说明还有空格要填, int b = blank[top][1];        //用a,b记录下top指向的元素作为当前试填空格的坐标int n = sd[a][b];             //用n记录当前空格中的数字,这个数字作为试填的“进度”,从这个数字加1往下试填for(n++;n <= 9;n++)     //将n加1后,一直循环到9进行试填{int ok = 1;                  //ok=1标志当前数字可行for(int k = 0;k < 9;k++)   //检测同行,同列,同块的数字是否有相同的{if(sd[a][k] == n || sd[k][b]== n || sd[(a / 3) * 3 + k / 3][(b/ 3) * 3 + k % 3] == n )  //同行,同列,同块的数字一起检测{ok = 0;  //如果同行,同列,同块某一处有相同数字,则ok=0,表示当前数字不可行break;    //不再往下检测,跳出此层循环,继续试下一个数字}}if(ok) break;    //如果ok保持为1,说明当前数字可行(否则肯定会被修改为0),跳出循环,不再往下试}if(n <= 9)   // 如果有一个数字可行,n<=9。否则,n=10 {sd[a][b] = n;  //将这个数字填入空格中top++;   //top加1,处理下一个空格}if(n > 9)   //如果试到9都不行的话,循环结束后n的值为10,此时要回退  {sd[a][b] = 0;  //回退时先将当前空格中数字改为0,相当于清零top--;   //回退1步}}printf("\n您的数独问题具有错误,请输入正确的数独问题\n");}

第三步,因为每填一个数,top就会进行加一的操作,然后一共有count个数需要填,所以当top等于count时,输出最终的结果。

if(top == count)   //因为每填完一个空格后top加1,填最后一个空格时top==count-1,填完后top加1即等于count{printf("最终结果为:\n");for(int s = 0;s < 9;s++)                        {                                                            for(int t=0;t<9;t++)                          {                                                          printf("%d  ",sd[s][t]);                   // 输出一个解}                                                        printf("\n");                                       }                                                            }

最后,将一个不完整的数独代入进行测验。

int main(void)
{int sd[9][9] = {  //  “世界最难数独”信息   8,0,0,0,0,0,0,0,0,0,0,3,6,0,0,0,7,0,0,7,0,0,9,0,2,0,0,0,5,0,0,0,7,0,0,0,0,0,0,0,4,5,7,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,0,6,8,0,0,8,5,0,0,0,1,0,0,9,0,0,0,0,4,0,0,};fill(sd);  //调用函数求解return 0;
}

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

  1. 01背包问题【回溯法求解】通俗易懂,适合小白

    本人此时还是一名研一的小菜鸡,刚学会了这个算法的基本概念,来总结一下,谁知道今后的我再看到这篇自己写的博客的时候会不会笑出来,哈哈哈哈哈哈哈哈,所以吗,错了的化大佬们评论指正就好了. 还有系列文章动态 ...

  2. php生成迷宫图片,PHP实现基于回溯法求解迷宫问题的方法详解

    本文实例讲述了PHP实现基于回溯法求解迷宫问题的方法.分享给大家供大家参考,具体如下: 引言 最近在leetcode上看了些算法题,有些看着很简单的很常用的东西,竟然一下子想不出来怎么求解,比如说:实 ...

  3. 回溯法求解N皇后问题及其时间复杂度分析

    回溯法求解N皇后问题及其时间复杂度分析 一.回溯法简介 1. 什么是回溯法? 2. 回溯法的时间复杂度分析 蒙特卡罗方法 蒙特卡罗方法在回溯法求解时间复杂度中的应用 二.回溯法求解N皇后问题 1. 回 ...

  4. 算法设计与分析 实验三 回溯法求解地图填色问题

    回溯法求解地图填色问题 一.实验目的与要求 1.实验基本要求: 2.实验亮点: 二.实验内容与方法 三.实验步骤与过程 1.未优化的回溯: (1)算法描述: (2)编程实现 (3)运行并测试: 2.对 ...

  5. 回溯法 | 求解装载问题

    问题描述: 有 n 个集装箱要装上一艘载重量为 W 的轮船,其中集装箱 i (1<=i<=n) 的重量,为wi.子啊装在体积不受限制的情况下,将尽可能重的集装箱装上轮船,当重量相同时要求选 ...

  6. n皇后问题-回溯法求解

    n皇后问题-回溯法求解 1.算法描述 在n×n格的国际象棋上摆放n个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. n皇后是由八皇后问题演变而来的.该问题 ...

  7. LeetCode之单词搜索(回溯法求解)

    题目 给定一个 m x n 二维字符网格 board 和一个字符串单词 word .如果 word 存在于网格中,返回 true :否则,返回 false . 单词必须按照字母顺序,通过相邻的单元格内 ...

  8. 回溯法解01背包问题(最通俗易懂,附C++代码)

    问题描述: 01背包问题是算法中的经典问题,问题描述如下: 对于给定的N个物品,第i个物品的重量为Wi,价值为Vi,对于一个最多能装重量C的背包,应该如何选择放入包中的物品,使得包中物品的总价值最大? ...

  9. C语言回溯法九宫格数独问题

    Problem H 数独游戏 时限:1000ms 内存限制:10000K 总时限:3000ms 描述: 数独游戏规则 在9阶方阵中,包含了81个小格(九列九行),其中又再分成九个小正方形(称为宫),每 ...

最新文章

  1. 加密软件究竟有哪些作用呢?
  2. Adam Optimization Algorithm
  3. Xamarin.Android 使用 SQLite 出现 Index -1 requested, with a size of 10 异常
  4. 华为服务器bmc默认地址_智能数据中心和智慧园区:华为的单点突破与全局效应...
  5. pandas之groupby分组与pivot_table透视
  6. Spring 配置多个数据源,并实现动态切换
  7. EIGRP特性试验笔记
  8. Web性能测试篇:AB 压力测试
  9. 终结者:借助ViewPager实现Fragment左右滑动
  10. c语言代码大全和详细解释_最详细的Simulink代码生成(C语言)
  11. Java导出excel合并单元格边框消失问题
  12. 天使投资人讨论区块链投资:区块链虚火还是真火?
  13. 【来龙去脉系列】机器学习入门必读
  14. VCS+dve+verdi仿真
  15. 汇编:动态画出一棵七彩圣诞树
  16. Kubernetes部署
  17. Pytorch 中的detach 和detach_
  18. audio muted属性绑定无效 vue
  19. STM32F0xx定时器输出PWM配置
  20. Bash 破壳漏洞Shellshock (CVE-2014-6271)复现

热门文章

  1. 川崎焊接机器人编程实例_川崎焊接机器人的九大优点
  2. 【NOI2005】智慧珠游戏,DLX的NOIP坎关。
  3. 常用电气图形符号和文字符号
  4. Ubuntu最新版本(Ubuntu22.04LTS)安装nfs服务器及使用教程
  5. 2017年三月初大厂前端面试总结
  6. PairProject 总结
  7. MySQL的DQL语言:2、条件查询
  8. jimogsh 推荐《Mathematica演示项目笔记》
  9. 利用ZjDroid对 捕鱼达人3 脱壳及破解过程
  10. 长安大学水利计算机专业等级,2016年长安大学计算机类(含计算机科学与技术、软件工程、网络工程等4个专业)专业最低分是多少?...