个人项目之数独的生成与数独残局求解——C语言实现
1、对项目的分析与初步计划:
- 起初拿到这个项目是非常懵逼的,因为涉及到很多个人的知识盲区,诸如:C语言文件的操作、命令行参数、Code Quality Analysis工具、性能分析工具Studio Profiling Tools、GitHub……。可以说在这之前根本就没有接触过这些东西。
- 虽然什么都不会,但不能什么都不做,于是我制定了以下计划:
- 什么都不管,先写好代码再说。
- 翻开《C 程序设计(第四版) 谭浩强》学习C文件的基本操作。
- 百度了解命令行参数。
- 其他的太缥缈了,走一步看一步啦。
2、具体实现过程:
- 根据项目要求,我把代码分成“生成数独终局”和“求解数独残局”两部分。
Creat_ShuDu(argv[]);//生成数独终局
Solve_shuDu(argv[]);//求解数独残局
- 生成数独终局:
- 对于这一部分,我先生成了一个叫“First line.txt”的文本文件。这个文件用来存储所有可能的数独第一排数据,当需要生成数独终局时,就从这个文件里挑一组数据出来完成数独第一行。(写完这句话我才发现我这不是多此一举吗?!根本没必要啊!)
- 如何生成一个完成的数独终局,这是一个问题。百度上给了多种方法,考虑到自己的能力,最终选择了暴力回溯法。
- 对于数独中的每一个小格,它只能填写1~9这9个数字,并且每两个小格间都存在着一定的联系,这给我们的回溯提供了依据。
- 项目要求生成足够的数独数目。一次性生成多个数独,我可以先写只生成一个数独终局的代码。
- 从某一小格的某一种可能出发, 搜索从这种情况出发所能达到的所有可能, 当这一条路走到” 尽头 “或者这条路失败的时候, 再倒回到上一步, 从另一个可能出发, 继续搜索. 直到得到足够的终局。
- 求解数独残局:
- 其实写完了“生成数独终局”,再写求解部分是非常简单的,因为他们的主要算法都是回溯。唯一的不同就是求解的时候,有些位置已经有了确定的数字。
3、关键代码说明:
在整个项目代码中最重要的代码当属judge(int i, int j)函数。
int judge(int i, int j) //搜索第( i , j )位置处可以存储的数字,找到解则返回1,否则返回0
{
|| j > ) ;//搜索结束
; k <= ; k++)
{
; // can 变量用于记录数字k能否放在 ( i , j ) 处
; m < i; m++) // 检查同一列是否出现过数字k
{
if (shuDu[m][j] == k) //该列出现过数字k
{
can = ;
break;
}
}
)
{
; n < j; n++) // 检查同一行是否出现过数字k
{
if (shuDu[i][n] == k) //该行出现过数字k
{
can = ;
break;
}
}
}
) // 检查在3×3的小方格中是否出现了同一个数字
{
) * + ; // (i,j)方格所在的3×3小方格i坐标的上限
) * + ; // (i,j)方格所在的3×3小方格在j坐标的上限
== ) up1 = i; //这是针对特殊情况的处理
== ) up2 = j;
; p <= up1; p++) /* 检查在3×3的小方格中是否出现了同一个数字 */
{
; q <= up2; q++)
{
if (shuDu[p][q] == k)
{
can = ;
break;
}
}
}
}
) //can==1说明数字k可以放在该位置上
{
shuDu[i][j] = k;
)
{
) == ) ; /* 到同一行的下一位置开始搜索 */
}
else
{
)
{
, ) == ) ; /* 到下一行的第一个空格开始搜索 */
}
else
{
num++;
if (num<numbers)
{
Print_shuDu(num);
}
else
{
Print_shuDu(num);
; /* i >= 9 && j >= 9 , 搜索结束 */
}
}
}
shuDu[i][j] = ; /* 关键这一步:找不到解就要回复原状,否则会对下面的搜索造成影响 */
}
else continue;//继续尝试其他数字
}
; /* 1到9都尝试过都不行,则返回递归的上一步 */
}
这段代码使用的是典型的回溯法。弄懂了这个函数,再写求解数独残局的函数就变的相当简单了。
4、代码优化:
- 因为我使用的是暴力回溯法,所以能够优化的地方确实不多。我主要优化的是“数独输出函数”。
void Print_shuDu(int n) //数独输出函数
- 起初我通过 fprintf() 函数将数据输出到文件,测试时输出1000000个数独终局需要近2分钟的时间。
- 后来我将这个函数改成 fputc()的输出方式,运行速度大大加快,对于1000000个数独只需 30左右,缩短了近四分之三的时间。
- 对此,我特意百度了一下原因。感兴趣的伙伴可以看看。https://blog.csdn.net/slimfox/article/details/1092709
5、后期各种测试:
- 性能分析如下:
-
- CPU使用率如下:
-
6、项目收获:
最大的收获当然是第一次基本独立完成了一个项目,虽然项目很小,做出来的东西很辣鸡。
- 将该文一开始提到的各种知识盲区大致熟悉了一遍,为以后的学习提供了方便。
- get到了一些小东西:
- fputc()比fprintf()快
- 在VS中scanf要写成scanf_s,为了更安全
- 在VS中输入一个字符串应写成 scanf_s("%s",s1,sizeof(s1));
- 在VS中打开一个文件应这样写 fopen_s(&fp, "sudoku.txt", "w");
附:PSP2.1表格
| PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) | 实际耗时(分钟) |
| Planning | 计划 | 60 | 120 |
| .Estimate | 估计这个任务需要多少时间 | 2000 | 1500 |
| Development | 开发 | 200 | 300 |
| .Analysis | 需求分析(包括学习新技术) | 30 | 60 |
| .Design Spec | 生成设计文档 | 60 | 40 |
| .Design Review | 设计复审(和同事审核设计文档) | 60 | 30 |
| .Coding Standard | 代码规范(为目前的开发指定合适的规范) | 120 | 100 |
| .Design | 具体设计 | 60 | 60 |
| .Coding | 具体编码 | 200 | 300 |
| .00Coed Review | 代码复审 | 30 | 60 |
| .Test | 测试(自我测试,修改代码,提交修改) | 60 | 180 |
| Reporting | 报告 | 60 | 120 |
| .Test Report | 测试报告 | 30 | 60 |
| .Size Measurement | 计算工作量 | 30 | 40 |
|
.Postmortem & Process Improvement Plan |
事后总结,并提出过程改进计划 | 30 | 30 |
| 合计 | 3030 | 3000 |
个人项目之数独的生成与数独残局求解——C语言实现的更多相关文章
- [2017BUAA软工]第一次个人项目 数独的生成与求解
零.Github链接 https://github.com/xxr5566833/sudo 一.PSP表格 PSP2.1 Personal Software Process Stages 预估耗时(分 ...
- 聊聊 Web 项目二维码生成的最佳姿势
在设计和实现的过程之后,你永远不知道部署上去的程序会已什么样的姿势运行. 本篇借一次生成二维码逻辑的不同实现,阐述 Web 项目中二维码生成的正确姿势. 文中如有批量,欢迎各位看客老爷拍砖.试运行前5 ...
- vue项目通过webpack打包生成的dist文件放到express环境里运行(vue+webpack+express)
1.首先需要的原料肯定是vue打包生成的dist文件 在vue项目目录下运行:npm run build,等待运行结束,会在项目目录下生成一个dist文件夹,里面会生成一些文件(如下图示) 小的项目文 ...
- 在定制工作项时,把“团队项目”作为变量获取生成版本信息
有用户最近提出这个需求: 通过工作项定制,新增一个字段用以保存项目Bug的"影响版本"信息,但是需要从当前团队项目的服务器生成纪录中获取版本的选项,类似默认模板中的"发现 ...
- GNU大型项目构建和覆盖率生成(第一篇)
目录 0. 序言 1. 项目描述 2. 项目构建 2.1 编译规则 2.2 构建过程 3. 覆盖率分析 0. 序言 在开始正文之前,请允许我先说明一下本文的目的和写作的动机,好让读者不惑. 我们知道, ...
- ABP项目中使用Swagger生成动态WebAPI
本文是根据角落的白板报的<使用ABP实现SwaggerUI,生成动态webapi>一文的学习总结,感谢原文作者角落的白板报. 1 安装Swashbuckle.core 1.1 选择WebA ...
- Android Studio] Gradle项目中添加JNI生成文件(.so文件)
转:http://blog.csdn.net/qiujuer/article/details/24209457 为了适应潮流使用Android Studio还是有半年多了! 对于从Eclipse迁移项 ...
- 在VS项目中通过GIT生成版本号作为编译版本号
上一篇博客写了如何在 .Net 项目使用 SVN 作为版本控制工具时生成与代码对应的组件版本号.虽然在公司一直使用 SVN ,但我却对 GIT 情有独钟(可能要归功于那段捣鼓 ROM 的时光),但少有 ...
- 米扑科技的开源项目:sitemap-php 自动生成网站地图
米扑科技旗下的产品,近期正在做SEO网站优化,其中子需求之一是调研实现了网站地图(sitemap.xml) 封装简化了许多功能模块,现在分享出来,源代码可在Github上下载,有简单的示例. Gith ...
随机推荐
- MaxCompute 图计算用户手册(上)
概要 ODPS GRAPH是一套面向迭代的图计算处理框架.图计算作业使用图进行建模,图由点(Vertex)和边(Edge)组成,点和边包含权值(Value),ODPS GRAPH支持下述图编辑操作: ...
- Arthas用法
简介 Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱. 当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决: 这个类从哪个 jar 包加载的? 为什么会报各种类相关的 ...
- oracle函数 last_day(d1)
[功能]:返回日期d1所在月份最后一天的日期. [参数]:d1,日期型 [返回]:日期 [示例]select sysdate,last_day(sysdate) hz from dual; 返回:2 ...
- 微信支付、支付宝支付和QQ钱包支付
最近忙于对接微信支付和支付宝支付,注册微信公众号,认证公众号,注册微信支付商户号并进行认证: 签约支付宝支付产品(手机网站支付.PC网站支付),注册支付宝企业账号(企业账号权限更大): 注册QQ钱包商 ...
- vscode golang vue配置
{ "files.autoSave": "off", "window.title": "${dirty}${activeEdito ...
- 20182019-acmicpc-asia-dhaka-regional F .Path Intersection 树链剖分
直接进行树链剖分,每次对路径区间内的所有点值+1,线段树进行维护,然后查询线段树的最大值的个数!!! 查询线段树区间最大值个数,可以先维护区间和,在维护区间最值,如果区间和等于区间最值乘以区间长度,那 ...
- getopt、getopt_long和getopt_long_only解析命令行参数
一:posix约定: 下面是POSIX标准中关于程序名.参数的约定: 程序名不宜少于2个字符且不多于9个字符: 程序名应只包含小写字母和阿拉伯数字: 选项名应该是单字符或单数字,且以短横 '-' 为前 ...
- js循环遍历数组(对象)
1,for循环 对于循环应该是最常用的一种遍历方式了,通常用来遍历数组结构. let arr = [a,b,d];for (let i=0; i<arr.length; i++){ consol ...
- 详解ThinkPHP支持的URL模式有四种普通模式、PATHINFO、REWRITE和兼容模式
URL模式 URL_MODEL设置 普通模式 0 PATHINFO模式 1 REWRITE模式 2 兼容模式 3 如果你整个应用下面的模块都是采用统一的URL模式 ...
- Taglib自定义万能标签扩展 DownLoad
http://www.thinkphp.cn/extend/538.html 用ThinkPHP的标签做网站觉得不够快速,就自己写了一个扩展,感觉挺好的,分享出来,给有需要的TPER. 复制代码 &l ...


