Suduku——软件工程项目实记

Suduku——软件工程项目实记

1. 项目描述

Github地址:SudukuProject - Github

通过分析,本次软工项目需要实现两个与数独有关的主要任务。
1.生成多个(1-106个)无重复的数独终局到文件。
2.求解多个(1-106个)数独残局,并将结果输出至文件。

2. PSP 2.1 表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 20
· Estimate · 估计这个任务需要多少时间 30 20
Development 开发 1000 1440
· Analysis · 需求分析(包括学习新技术) 200 300
· Design Spec · 生成设计文档 60 90
· Design Review · 设计复审(和同事审核设计文档) 30 30
· Coding Standard · 代码规范(为目前的开发制定合适的规范) 60 60
· Design · 具体设计 120 180
· Coding · 具体编码 300 450
· Code Review · 代码复审 30 30
· Test · 测试(自我测试,修改代码,修改提交) 200 300
Reproting 报告 270 330
·Test Report · 测试报告 180 240
·Size Measurement · 计算工作量 30 30
·Postmortem & Process Improvement Plan · 事后总结,并提出改进计划 60 60
合计 1300 1700

3. 确定解题思路

1)生成数独终局
  • 第一种想法是暴力回溯法求解,这个时候分两种填入方法。第一种是从左上到右下,每次将1-9以随机位置填入一行,通过随机化回溯调换数字位置,使符合规则。第二种是按照数独规则,每次填入一种数字,填入后行列宫格均不重复,再开始填入下一个数字。
    这种方法思路比较清晰,生成的数独比较多样,因为每个数独只有9*9大小,所以预测回溯用时在经过优化后还是可以接受的,将其加入待用方案。

  • 第二种方法是模板法,这种方法是经过查找各种资料找到的。模板法的第一步都是先生成一种合法的数独盘面作为模板,根据后续对模板处理的不同思路,将其分为三种比较有代表性的方法。

    1. 第一种的处理是以宫格为单位的矩阵转换法,生成合法的中间3*3宫格后,经过小宫格的行变换填充左右相邻宫格,有2!种填充方法,经过小宫格列变换填充上下相邻宫格,有2!种填充方法再经过行列变换结合填充四个角上的宫格,有4!*2种填充。采用这种方法,每种中间宫格对应192种填充方式,中间宫格共有9!种填充方式,计算得这种方法共能生成362880×384种,大于106种,将其加入待选方案。
    2. 第二种是在生成基本模板终盘后,用a-i替换数字1-9,对模板进行行列变换,1-3、4-6、7-9行每3行或列中单独变换。由于左上第一个数字固定,1-3行有2!种交换结果,4-6行有3!种变换结果,7-9行有3!种变换结果,计算可得共有8!×3!×2!×3!=40320×72种数独终盘,大于106,将其加入待选方案。
    3. 第三种处理是以行列为单位,对数独行列模板进行平移变换生成新的行或列,为了简化说明,这里只以行变换为例。每一确定的行的数字向右平移后,可得到9个不同的行,把它们按一定顺序排列即可得到符合规则的数独盘面。
      令Sn为第n行向右平移的格数,S1可认为等于0,|S2-S1|≥3且|S3-S2|≥3同时成立即可得到合格的前三行,第4-6与第7-8行同理,同时S1到S9互不相等。在此种方法中用a-i代替数字1-9,由于第一行左边第一个数字要求固定,因此第一行有8!种填充方式,平移时,前三行有{0,3,6}{0,6,3}两种平移方式,4-6行可分别以1、4、7以2、5、8进行3!×2种平移,7-9行同理。
      此种方法可得8!×3!×2×3!=1451520×2种数独终盘,大于106,将其加入待选方案。
  • 经过对问题得分析,以上方案都可以做出尝试,但结合实现的难度,个人选择模板法,又因为后两种模板法有一定相似之处,结合代码实现的复杂度,选择模板较为简单的平移法

2)数独残局求解
  • 求解数独时也准备了两种方法。一种是采用暴力回溯法,用DFS深度优先法进行优化。一种是Dancing Links解法,类比精准覆盖问题求解。由于第二种方法实现比较复杂,准备先用第一种方法实现一遍看性能怎样。
  • 在使用回溯算法中,经过学姐提醒,借鉴Forward-checking算法进行优化,加入约束传播步骤加快求解数独的速度与精度。

4. 实现过程设计

  • 程序主要实现生成数独及求解数独两种功能,因此将程序分为两大模块。
  • 首先,通过读取调用命令判断需要实现的功能,并进入相关模块。本程序考虑了多种可能出现的调用指令,并给出了相应的错误提示,报错能力较强。
    1. 在生成数独模块中,主要函数为ConnectChanges,这部分函数实现随机数的生成及对模板的填充,将填充好的数独终盘存入数组,并通过调用RowChanges函数对模板进行行模板的平移变换,最后当主函数判断出所有数独终盘已经生成完毕时,调用CreatOutput函数进行统一的文件输出。
    2. 在求解数独中,主函数先调用GetProblem读入81个数字,判断为数独题目后,调用SolveSudoku 函数进行求解,此函数为求解部分的主要函数,也为回溯部分,此函数通过调用 MarkVis函数对出现过的数字进行标记,并通过Check判断填入数字是否合法,若不合法则回溯。当此数独完成后,调用SaveSolution函数进行规范输出。

5. 性能改进与性能分析

  • 因本项目对程序运行时间有所限制,因此,本程序在设计和编码阶段都做了大量优化,主要体现在以下方面。
    1.经过资料搜索,程序的输入输出部分将占用大量时间,因此,为了减少输出次数,优化输出时间,在生成数独模块中,掘弃了生成一个终盘即输出的做法,而是申请了一个一维大数组,将数字及换行符还有空格存入,虽然在代码实现阶段会复杂一点,但只用打开一次文件,就可以进行整个结果数组的输出。
    2.在设计初期,想用更容易实现的暴力搜索,但后来的查资料过程中,接触到了各种算法,通过对这些算法的借鉴和学习,对回溯进行了条件约束,使回溯步数大大减少,优化了程序运行时间。
  • 因此,在代码初版完成后,针对性能改进方面基本没有太大的更改。
  • 以下是程序生成1000盘数独终盘,所用时间及函数使用情况。总用时4.055秒。(因未知原因函数名发生了改变,但看函数调用逻辑基本不影响阅读。)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

6. 代码说明<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值