软件工程个人项目— 数独

软件工程个人项目— 数独

1120173032 王晗

Github:https://github.com/lion-han/sudoku

目录

软件工程个人项目— 数独

PSP2.1 表格

个人日报:

程序功能简介:

结题思路:

生成终局

生成题目

求解数独

设计实现过程(另一篇博客)

                  代码组织

                  代码说明

      单元测试(另一篇博客)

      性能分析(另一篇博客)

 


PSP2.1 表格

PSP2.1Personal Software ProcessStages预估耗时(分钟)实际耗时(分钟)
Planning计划6055
Estimate估计这个任务需要多少时间2020
Development开发700700
Analysis需求分析 (包括学习新技术)380450
Design Spec·生成设计文档10060
Design Review设计复审 (和同事审核设计文档)5030
Coding Standard代码规范 (为目前的开发制定合适的规范3030
Design· 具体设计8060
Coding具体编码7501200
Code Review代码复审6080
Test测试(自我测试,修改代码,提交修改)2501160
Reporting报告240480
Test Report测试报告60120
Size Measurement计算工作量3030
Postmortem & Process Improvement Plan事后总结, 并提出过程改进计划4050
 合计28504520

个人日报:

日期工作情况耗时
12.23分析并选题60min
12.24创建博客、github仓库、需求分析、解题思路90min
12.25解题思路50min
12.26学习DLX算法、生成数独终局,github托管调试190min
12.27完成数独题目生成部分,github托管成功170min
12.28完成解数独部分(暴力解),加入命令行分析与报错,进行代码结构化调整250min
12.29vs项目出错,修改bug,重建项目,push180min
1.14发现没有进行行的交换,修改代码,实现生产1200000个不同的数独150min
1.15学习单元测试工具之间的区别,学习安装使用gtest进行单元测试200min
1.16优化数独生成时间,尝试不同文件读写方式240min
1.17学习vs性能分析工具,进行string字符串处理的优化,文件读写的优化300min
1.18继续学习单元测试,完成单元测试,进行覆盖率,进行代码分析,修改错误360min
1.19补充单元测试,组织博客内容300min

程序功能简介:

实现一个命令行程序,具有以下功能:

  1. 生成不重复的N个数独终局至文件(1<=N<=1000000)

  2. 读取文件内的数独问题,求解并将结果输出到文件

具体需求详见软件工程基础-个人项目文档

结题思路:

生成终局

       最开始的想法是一位一位的产生数独的每位数字,但是总也想不出高效的解决方法。于是上网查了些资料,并通过自己画图研究数独时发现,想要生成数目庞大的数独终局,不能通过随机的分配或者一位一位产生,必须通过一定规律的变化得到。

       我发现通过确定第一行的数,后面7行通过对第一行不同的移位可产生一个数独终局。由于每个3*3的方块内不能有重复的数,所以1、2、3行,4、5、6行,7、8、9行内位移必须大于等于3,不然会出现重复。

       通过变化第一行的数顺序,其余7行移位规律不变(),可产生8!=40320个终局(第一位固定,后面7行移位规律相同)

之后可以通过2、3行,4、5、6行,7、8、9行内交换任意两行可得到不同的矩阵,共2*6*6=72种变化

       通过上述变化可产生 8! *(2*6*6)=2903040>1e6 可满足条件,并且分析后不会产生相同的数独。

       但是如何进行第一行的全排列是一个问题,首先我想到的是,通过遍历来解决,但是9个数字需要9^9 的时间消耗来解决,显然不可行,然后我想到类似于桶排序的方法确定每位是否被用过,但是并不能提升效率。然后上网搜索,发现一种康托展开的方法,它是一个全排列到一个自然数的双射,可以把一个自然数转换成一个对应的全排列,也可以把一个全排列转换成一个对应的自然数,使用逆康托展开可以在O(N*N)的时间复杂度下形成一个全排列。效率有了很大的提升。实现个小模块之后,通过与ACM室友的交流,我了解到c++里有一个产生全排列的函数 next_permutation 可以产生全排列。于是我去网上搜索它的实现原理,next_permutation 通过分析全排列的规律来交换数字反向操作实现下一个全排列,时间复杂度可达O(N),已经非常好了。

       全排列问题解决了,如何进行第一行的移位呢,首先顺序移位是有点慢的O(N),使用链表可达到O(1),但是链表比较麻烦,最终想出了将第一行数字再连接一个第一行数字,通过每次取不同位置的9个数即可,可达到O(1)。

       然后便是交换数独的行,形成新的数独,由于要求第一行首为与学号有关的特定数,所以第一行不动,交换其他行。首先我想到的是实现一个函数用来交换特定行的内容,但是这不仅要求交换两行,而且要求交换3行,且交换的规律是特定的很难通过递归循环来实现。于是我想到根据上面形成的初始数独,对他的行的排列写一个30*9的数组,规定行的顺序,然后按照顺序进行数独的生成。

生成题目

       由于上一步已经产生了许多数独终局,所以数独问题的产生就可以依靠产生的数独终局文件了。读取数独终局文件,通过输入参数n,可以生成n个数独题目。题目的生成通过随机给数独的位置赋值0来解决。也可以加入一个空白比例参数实现题目的难度级别。再写入文件。

求解数独

       开始时感觉数独求解应该很费时间,所以先去网上搜索了一下数独的求解问题。发现了一个DLX算法用来解决精准覆盖的问题,刚好可以用在解数独上,它通过一种双向十字链表的数据结构加上搜索来解决问题。但是把它用来解数独实践起来还是有点难度。毕竟是一个软件工程项目,不仅仅是程序设计问题,所以我就先使用简单的DFS(深度优先搜索)进行数独的求解。在实现后发现挖空率在60%都可以非常快的求解出来,所以就先使用DFS来解数独了。分析挖空率为50%的数独,发现实际上求解还是挺简单的,每个空可填的数字都非常有限。所以决定使用DFS来实现数独求解。

其他博客:

        设计实现过程(另一篇博客)

        单元测试(另一篇博客)

        性能分析(另一篇博客)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值