数独

题目描述

数独是根据 9 × 9 9 \times 9 9×9 盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫内的数字均含 1 − 9 1 - 9 1−9 ,不重复。每一道合格的数独谜题都有且仅有唯一答案,推理方法也以此为基础,任何无解或多解的题目都是不合格的。

芬兰一位数学家号称设计出全球最难的“数独游戏”,并刊登在报纸上,让大家去挑战。

这位数学家说,他相信只有“智慧最顶尖”的人才有可能破解这个“数独之谜”。

据介绍,目前数独游戏的难度的等级有一到五级,一是入门等级,五则比较难。不过这位数学家说,他所设计的数独游戏难度等级是十一,可以说是所以数独游戏中,难度最高的等级。他还表示,他目前还没遇到解不出来的数独游戏,因此他认为“最具挑战性”的数独游戏并没有出现。

输入格式

一个未填的数独。

输出格式

填好的数独。

样例 #1

样例输入 #1

8 0 0 0 0 0 0 0 0
0 0 3 6 0 0 0 0 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

样例输出 #1

8 1 2 7 5 3 6 4 9
9 4 3 6 8 2 1 7 5
6 7 5 4 9 1 2 8 3
1 5 4 2 3 7 8 9 6
3 6 9 8 4 5 7 2 1
2 8 7 1 6 9 5 3 4
5 2 1 9 7 4 3 6 8
4 3 8 5 2 6 9 1 7
7 9 6 3 1 8 4 5 2

提示

2022-04-17 @farteryhr 贡献了三组 hack 数据。加入了其中两组。第三组过强(来源:https://www.dcc.fc.up.pt/~acm/sudoku.pdf),放在下边供自测。

9 0 0 8 0 0 0 0 0
0 0 0 0 0 0 5 0 0
0 0 0 0 0 0 0 0 0
0 2 0 0 1 0 0 0 3
0 1 0 0 0 0 0 6 0
0 0 0 4 0 0 0 7 0
7 0 8 6 0 0 0 0 0
0 0 0 0 3 0 1 0 0
4 0 0 0 0 0 2 0 0

输出

9 7 2 8 5 3 6 1 4
1 4 6 2 7 9 5 3 8
5 8 3 1 4 6 7 2 9
6 2 4 7 1 8 9 5 3
8 1 7 3 9 5 4 6 2
3 5 9 4 6 2 8 7 1
7 9 8 6 2 1 3 4 5
2 6 5 9 3 4 1 8 7
4 3 1 5 8 7 2 9 6

不再赘述数独游戏的规则

思路

见到这种填数题,大概率需要用到深度优先搜索,其大致思路就是暴力枚举,如果当前情况下这种填法无法满足题意,便会回溯寻找下一种情况,持续下去,一定会搜索到满足题意的情况
假设我们先填了1,然后下一个点尝试1,不成功便尝试2,一直到9,如果都不行,说明先填的1存在问题,将先填入的1改成2,这样循环下去。

由于这道题建立在数独游戏的背景之上,所以我们需要关注游戏规则。数独要求每一行,每一列,每一宫不能有同样的数字出现,可以填入的数字为1到9,那么我们可以设置四个数组

int hang[9][10]={0},
lie[9][10]={0},
pand[9][10]={0},//即数字盘,先初始化为0
gong[3][3][10] = {0};

其中,hang[x][i] = 0代表i这个数字在第x行没有被填过,lie[y][i] = 0代表i这个数字没有在第y列出现过
需要注意的是对于宫数的判断,我可以举一个例子,我们数盘第一行第一列的数字坐标为(0,0)那么对于第一行第三列的数字来说,它的坐标为(0,2)。为什么纵坐标为2而不是3呢?因为我们的起始坐标为0,对于这个点来说它属于第一宫,对应gong[0][0],他紧接着右边的点属于第二宫,也就是说(0,3)对应第二宫,也就是gong[0][1]所以我们可以得到宫数组的定义和表达式
gong[x/3][y/3][i] = 0代表着i这个数字没有在对应宫出现过。这里的x和y不会等于9,因为x是从零开始,最多等于8

既然要用到深度优先搜索,我们需要先考虑回溯的条件,我们可以确定横坐标然后搜索纵坐标。如果正好完成了整个数独,刚好填入最后一个数字的时候,也就是临界情况为x == 8 && y == 8,我们已经确定了搜索思路,那么完成后,紧接着x和y对应的值就是x == 8 && y == 9,这种情况下就应该直接输出整个数盘

if(x == 8 && y == 9 ){for(int i = 0; i < 9; i++){for(int j = 0; j < 9; j ++){cout<<pand[i][j]<<" ";}cout<<endl;}exit(0);}

如果我们把exit(0)换成return,那么会有一个测试点超时!

我们可以思考这个过程,在完成全部填入之前,x相对于y变化很是缓慢,那么我们就先考虑y到临界的情况,在y为8时,填入数字后,根据顺序,y的值便成了9,那么这个时候就应该在下一列的第一行填入数字,代码如下

if(y == 9){    dfs(x+1,0);}

对于正常情况,因为在填入过程中会有回溯过程,所以我们应该判断这个点是否存在数字,如果存在,那么跳过这个点就行,如果没有,我们需要先判断填入的数字是否在行,列,宫出现过,如果出现,就跳过,如果没有,就进行正常填入,然后进行回溯。
因为这是一个暴力搜索的过程,所以我们可以从1开始填入

else{if(pand[x][y] != 0){dfs(x,y+1);}if(pand[x][y] == 0){for(int n = 1; n <= 9; n++){if(!hang[x][n] && !lie[y][n] && !gong[x/3][y/3][n]){pand[x][y] = n;hang[x][n] = 1;lie[y][n] = 1;gong[x/3][y/3][n] = 1;dfs(x,y+1);hang[x][n] = 0;lie[y][n] = 0;gong[x/3][y/3][n] = 0;pand[x][y] = 0;}}}}

!hang[x][n] && !lie[y][n] && !gong[x/3][y/3][n]这段代表n这个没有在行,列,宫出现过。

为什么要把填入数字盘的数字也抹掉呢?对应pand[x][y] = 0;就是因为最开始说的,如果这个数字不合适,就会回溯然后寻找新的可能。换句话说,先前填入的数字不一定是正确的,如果发现填不下去,就会返回。

因为题目中给了部分数字,所以我们在main函数里面需要对这些数字进行操作

int main()
{for(int i = 0; i < 9; i++){for(int j = 0;j < 9;j++){cin>>pand[i][j];if(pand[i][j] > 0){hang[i][pand[i][j]]=1; //pand[i][j]代表的是一个数lie[j][pand[i][j]] = 1;gong[i/3][j/3][pand[i][j]] = 1;} }}dfs(0,0);return 0;}

对题目中已经给的数字,相当于已经出现过了,让对应行列宫的值等于一即可。

完整代码:

#include<iostream>
#include<algorithm>
using namespace std;
int hang[9][10]={0},lie[9][10]={0},pand[9][10]={0},gong[3][3][10] = {0};
void dfs(int x,int y){if(x == 8 && y == 9 ){for(int i = 0; i < 9; i++){for(int j = 0; j < 9; j ++){cout<<pand[i][j]<<" ";}cout<<endl;}exit(0);}if(y == 9){    dfs(x+1,0);}else{if(pand[x][y] != 0){dfs(x,y+1);}if(pand[x][y] == 0){for(int n = 1; n <= 9; n++){if(!hang[x][n] && !lie[y][n] && !gong[x/3][y/3][n]){pand[x][y] = n;hang[x][n] = 1;lie[y][n] = 1;gong[x/3][y/3][n] = 1;dfs(x,y+1);hang[x][n] = 0;lie[y][n] = 0;gong[x/3][y/3][n] = 0;pand[x][y] = 0;}}}}}
int main()
{for(int i = 0; i < 9; i++){for(int j = 0;j < 9;j++){cin>>pand[i][j];if(pand[i][j] > 0){hang[i][pand[i][j]]=1;lie[j][pand[i][j]] = 1;gong[i/3][j/3][pand[i][j]] = 1;} }}dfs(0,0);return 0;}

有不清楚或者错误的地方请指出

洛谷 数独 详细解析相关推荐

  1. 洛谷——P1597 语句解析(两种解法)

    P1597 语句解析(两种解法) 题目背景 木有背景-- 题目描述 一串长度不超过 255 的 PASCAL 语言代码,只有 a,b,c 3 个变量,而且只有赋值语句,赋值只能是一个一位的数字或一个变 ...

  2. [洛谷P1074] 靶形数独

    洛谷题目链接:靶形数独 题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博 ...

  3. 倍增:喷泉 深度解析(洛谷P7167)

    洛谷传送门 解析 什么破题 数据范围来看很明显最多到nlogn 首先,对于样例进行一下分析: 我们可以把它转化为一棵树: 每一个根都有对应的权,给你一个结点和加权和,问能爬到哪里 既然是树,自然要找爸 ...

  4. 洛谷P1074 靶形数独 [搜索]

    题目传送门 题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教, Z 博士拿出了 ...

  5. 洛谷 10月 csp-s 模拟赛 T1,T2解析及代码

    洛谷 10月 csp-s 模拟赛 T1,T2解析及代码 T1 Magenta Potion 题目描述 给定一个长为 nnn 的整数序列 aaa,其中所有数的绝对值均大于等于 222.有 qqq 次操作 ...

  6. 洛谷题目---P1784 数独

    题目描述 数独是根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行.每一列.每一个粗线宫内的数字均含1-9,不重复.每一道合格的数独谜题都有且仅有唯一答案,推理方法也以此为基础,任何无 ...

  7. 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释...

    P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...

  8. 【洛谷】P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布(详细代码)

    [洛谷]石头剪刀布是常见的猜拳游戏:石头胜剪刀,剪刀胜布,布胜石头.如果两个人出拳一 样,则不分胜负.在<生活大爆炸>第二季第8集中出现了一种石头剪刀布的升级版游戏. 1.[题目描述] 2 ...

  9. 【洛谷】 P1424 小鱼的航程(改进版)(详细代码)

    [洛谷]有一只小鱼,它平日每天游泳 250 公里,周末休息,假设从周 x 开始算起,过了 n天以后,小鱼一共累计游泳了多少公里呢? 1.[题目描述] 2.[代码] 1.[题目描述] 题目背景 原来的题 ...

最新文章

  1. Python组合数据类型之序列类型
  2. 实现不可变类如何禁止子类化?
  3. .重要开源协定的比较以及区别
  4. 开年趣图汇总:对不起,让你笑了这么久
  5. 将一个16进制数转化为10进制数
  6. [Node.js] 模块化 -- http服务器模块
  7. js面向对象的程序设计 --- 上篇(理解对象)
  8. 常见数通设备镜像制作模板
  9. 抓linux肉鸡教程视频,超简单的菜鸟网吧抓肉鸡教程
  10. qss设置平面按钮_QToolButton设置QSS
  11. 开源3D建模软件FreeCAD基础介绍与入门
  12. 常用颜色的RGB值及中英文名称
  13. 计算机桌面空白图标如何删除,桌面上有两个i空白文件的图标删不掉怎么办急急急...
  14. apache beam java api_Apache Beam的基本概念
  15. 2018清明假期旅游预测报告:全国游客人次预计破亿
  16. python delphi 比较_Python4Delphi注意事项
  17. Minecraft多人联机服务器配置
  18. mysql5.7.20 安装过程记录
  19. week3note函数
  20. 几个简单实用的vbs命令

热门文章

  1. php上传头像的代码,php实现文件上传及头像预览功能
  2. linux通过md5验证文件完整性,Linux下校验下载文件的完整性(MD5,SHA1,PGP)
  3. 神经网络的特点及应用
  4. goroutine基本用法
  5. 计算机专业 英语六级作文,英语六级作文范文 计算机和人 Computer and Man
  6. 如何将谷歌浏览器安装在D盘
  7. 【软件建模与UML】
  8. SLM6500原厂2A同步降压型锂电池充电电路
  9. IEDA跑若依后台跑不出来
  10. matlab怎么画两个自变量的图_tcpip四层模型怎么画?画模型图的好用软件推荐