数独DFS求解

  • 简单数独的DFS求解
    • 1. 问题
    • 2.求解
      • 2.1 数据结构设计
      • 2.2 算法设计
      • 2.3 主要代码
        • 1.数独递归处理函数 sudoku_try
        • 2.检测函数 test
    • 3.完整代码

简单数独的DFS求解

1. 问题

给出9×9的标准数独,使用C语言编程完成这个数独的求解。

数独数独(shù dú)是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复 [1] 。

数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。

2.求解

2.1 数据结构设计

数独的定义决定了在C语言中使用一个二维数组就能完美的解决问题,所以这里使用9×9的二维数组存储数独,其中使用0表示需要填入数字的空格。

例如以上数独可以使用如下数组数据表示:

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

以上0表示数独中需要填入数组的空格

考虑到程序的可扩展性,比如解决超级数独的情况,代码中使用#define N 9这样的预定义表示数独大小。

2.2 算法设计

本案中可以暴力1-9从最左上角开始逐个尝试,但是关键问题是如何使用代码控制当发现尝试的数字不符合要求,回退到上一个数字的分析状态,然后尝试上一个数字的其他情况。其实这种情况是典型的DFS应用场景。

也就是说在每一个需要填写数字的位置,可以1-9逐个尝试 ,而每一个尝试又是可以递归成为对下一个位置1-9数字的尝试。

梳理一下算法如下:

  1. 判断是否已经将所有空格填满,如果填满输出数独然后直接退出程序。
  2. 判断当前需要处理的数独格子中,是否为0。
    • 如果为0,表示当前格子是一个需要填入数字的空格,那么可以1-9尝试填入一个数字,并验证是否满足要求。

      • 如果满足要求,那么暂时使用这个结果,并对下一个格子使用本算法递归分析。
      • 如果所有1-9都不能满足,那么表明上一次填入的数字是错误的,所以要回溯到上一次分析状态中(这里实际上是可以通过递归函数的返回实现)。注意:由于前面的尝试过程中,已经在数独中尝试填写了各种数字,这时候回退上一层调用前,必须先恢复原来状态,也就是将单元格设置为0。
    • 如果为1,表示当前单元格中原来就有数字,不需要我们处理,那么可以跳过这一个,处理下面一个格子。

2.3 主要代码

1.数独递归处理函数 sudoku_try

void sudoku_try(int s[N][N], int x, int y){int i;if ( x == N ){  /* 当前处理到N行了,也就是0~N-1都填完了,结束!*/printf("\n");print(s);   /* 输出数独 */exit(0);    /* 退出程序 */}if ( s[x][y] == 0 ) {for ( i=1; i <= N; i++ ) {if ( test(s, x, y, i) ) {s[x][y] = i;sudoku_try(s, (y+1) / N + x, (y+1) % N);}}s[x][y] = 0; /* 回退到上一层递归调用前,消除前面尝试遗留的数据。*/}else{sudoku_try(s, (y+1) / N + x, (y+1) % N);}
}

请注意以上代码中第5,15和18行代码含义,有助于理解。

2.检测函数 test

int test(int s[N][N], int x, int y, int k){int i, j;for (i = 0; i< N; i++) { /* 分别行列检测是否有k已经存在 */if ( s[x][i] == k || s[i][y] == k ) return 0;}/* 检测各自所在小9宫格 */for ( i = x / 3 * 3; i < x / 3 * 3 + 3; i++ )for ( j = y / 3 * 3; j < y / 3 * 3 + 3; j++ )if ( s[i][j] == k ) return 0;return 1;
}

3.完整代码

#include <stdio.h>
#include <stdlib.h>#define N 9int  test (int s[N][N], int x, int y, int k);
void print(int s[N][N]);
void sudoku_try(int s[N][N], int x, int y);int main (int argc, char *argv[])
{int sudoku[][N] = {{0, 6, 3, 0, 0, 7, 8, 0, 0},{0, 1, 2, 3, 0, 0, 5, 0, 0},{0, 0, 5, 0, 0, 0, 0, 1, 0},{0, 5, 0, 4, 0, 0, 0, 0, 0},{0, 3, 7, 0, 0, 0, 4, 9, 0},{0, 0, 0, 0, 0, 2, 0, 6, 0},{0, 8, 0, 0, 0, 0, 6, 0, 0},{0, 0, 4, 0, 0, 6, 7, 8, 0},{0, 0, 6, 2, 0, 0, 9, 3, 0},};print(sudoku);sudoku_try(sudoku, 0, 0);return 0;
}void sudoku_try(int s[N][N], int x, int y){int i;if ( x == N ){printf("\n");print(s);   /* 求一个解后退出,如果需 */exit(0);    /* 要求出所有解,怎么修改?*/}if ( s[x][y] == 0 ) {for ( i=1; i <= N; i++ ) {if ( test(s, x, y, i) ) {s[x][y] = i;sudoku_try(s, (y+1) / N + x, (y+1) % N);}}s[x][y] = 0; /* 请解释语句作用? */}else{sudoku_try(s, (y+1) / N + x, (y+1) % N);}
}int test(int s[N][N], int x, int y, int k){int i, j;for (i = 0; i< N; i++) {if ( s[x][i] == k || s[i][y] == k ) return 0;}for ( i = x / 3 * 3; i < x / 3 * 3 + 3; i++ )for ( j = y / 3 * 3; j < y / 3 * 3 + 3; j++ )if ( s[i][j] == k ) return 0;return 1;
}void print(int s[N][N]){int i, j;for ( i = 0; i < N; i++ ) {for ( j = 0; j < N; j++)printf("%3d", s[i][j]);printf("\n");}
}

本例中代码运行结果如下:

可以使用以上代码,试试 https://www.sudoku.name/index-cn.php 网站上的数独,算一下吧

简单数独的DFS求解相关推荐

  1. java课程 数独 文库_一次数独生成及求解方案的剖析(Java实现)

    数独生成及求解方案剖析(Java实现) 关键词 数独9x9 数独生成 数独解题 序言 最近业务在巩固Java基础,编写了一个基于JavaFX的数独小游戏(随后放链接).写到核心部分发现平时玩的数独这个 ...

  2. 使用dfs求解修道士和野人问题

    原文链接: 使用dfs求解修道士和野人问题 上一篇: js Set 的使用 下一篇: VMware 挂载U盘 1.问题描述 :这是一个古典问题.假设有n个道士和n个野人准备渡河.但只有一条能容纳c人的 ...

  3. UVALive 3351 Easy and Not Easy Sudoku Puzzles 位运算~判断简单数独

    题意:给定一个9*9的数独,要求判断是否为简单数独. 数独:对于每一行每一列或者子方格内,只能填1~9这几个数,并且每个数字只能出现一次,比如说: 如果一个9*9的数独是简单数独的话,这个数独的解是独 ...

  4. 软件工程基础个人项目——数独终局生成求解

    目录 1.源代码的GitHub链接: 2.PSP表格(预估): 3.题目要求: 4.解题思路: 1)数独游戏规则 2)生成数独终局 2)求解数独 5.设计实现过程: 第一部分:sudoku类的构建 第 ...

  5. 一个简单数独求解的算法

    突发奇想,想解决一个数独的求解算法 直接贴代码吧! #include <stdio.h> #include <sqlite3.h> #include <string.h& ...

  6. POJ-2676 Sudoku(简单数独-dfs深搜)

    Sudoku Time Limit: 2000MS Memory Limit: 65536K 题目链接http://poj.org/problem?id=2676 Description Sudoku ...

  7. 基于C++和QT实现的简单数独游戏软件

    资源下载地址:https://download.csdn.net/download/sheziqiong/85660211 一.实验题目与要求 本次实验主要内容是实现一个简单的数独软件,具体要求如下: ...

  8. C语言简单数独游戏终盘生成

    前言 这一篇文章介绍的是移动变换法,有详细的移动变化法的图文解析,在文末有完整的可用于查看移动变换法生成数独终盘过程的代码 实现思路 移动变换法这一方法是很简单的一种方法,实现起来也比较容易,但同时它 ...

  9. UVA572 Oil Deposits DFS求解

    小白书上经典DFS题目. 1. 递归实现 // from: https://www.cnblogs.com/huaszjh/p/4686092.html#include <stdio.h> ...

  10. 3109. [CQOI2013]新数独【DFS】

    Description Input 输入一共15行,包含一个新数独的实例.第奇数行包含左右方向的符号(<和>),第偶数行包含上下方向的符号(^和v).   Output 输出包含9行,每行 ...

最新文章

  1. Maven 传递性依赖
  2. PCL:自定义创建带颜色的点云保存后rgb是一个很大的数,由x y z rgb解包为x y z r g b
  3. Nat. Commun | 基于网络的药物组合预测
  4. ubuntu下的win交叉编译
  5. Docker 从Docker Hub 拉取镜像慢怎么办?
  6. ArcGIS AO中控制图层中要素可见状态的总结
  7. 用SSDT方法恢复冒险岛的部分函数
  8. 我想和你一起去这样一个地方
  9. cwinthread*线程指针怎么销毁结束_C++知识点:智能指针
  10. java linux解压_linux整套java环境解压版
  11. python3有什么用_Python 3.9的到来到底是意味着什么
  12. error lnk2001: mysql_使用mysql时的链接错误 | 学步园
  13. C语言把浮点数转换为二进制数的方法和示例
  14. 夏侯南溪搭建目标检测模型——文件结构设计篇
  15. 使用Slim框架创建一个JSON RESTfull API
  16. Linux一些基本概念
  17. Linux交换内存10g,Linux服务器只使用60%的内存,然后交换
  18. OpenGL 凹凸贴图实例
  19. Vue 状态管理与与SSR详解
  20. javaScript---异步那些事(promise)(21/11/8)

热门文章

  1. 路畅畅云固件升级教程_【图】【折腾导航】路畅导航固件升级、刷机、实现一机多图教程!...
  2. Win7 便签设置字体方法
  3. 易语言大漠透明图制作与使用
  4. 常用游戏分析工具 之 PChunter 及 procexp 使用心得
  5. 建模助手 —『 CAD图层管理 』Revit视图干净清爽
  6. java计算机毕业设计中国民航酒店分销系统源码+数据库+系统+lw文档
  7. endnote 参考文献加序号_EndNote插入文献序号排序混乱怎么破 | 科研动力
  8. html设置表单禁止修改群名片,如何设置禁止管理员修改qq群名片
  9. matlab所有画图函数,matlab所有画图函数
  10. 多目标优化算法(一)NSGA-Ⅱ(NSGA2)