2020软件工程作业03
格式(必做)
为了方便其他学校的老师或者助教了解课程实况,请大家在作业开头添加格式描述:
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1/homework/10494 |
这个作业的目标 | 实现一个命令行程序sudoku |
作业正文 | https://i-beta.cnblogs.com/posts/edit |
其他参考文献 | https://www.csdn.net/ |
1.Github项目地址
github.com/Z624/sudoku/blob/master/20177725
2.PSP表格
PSP是卡耐基梅隆大学(CMU)的专家们针对软件工程师所提出的一套模型:Personal Software Process (PSP, 个人开发流程,或称个体软件过程)。
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 60 |
Estimate | 估计这个任务需要多少时间 | 1900 | 1820 |
Development | 开发 | 240 | 300 |
Analysis | 需求分析 (包括学习新技术) | 240 | 180 |
Design Spec | 生成设计文档 | 100 | 120 |
Design Review | 设计复审 | 120 | 80 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 60 | 60 |
Design | 具体设计 | 120 | 180 |
Coding | 具体编码 | 240 | 180 |
Code Review | 代码复审 | 180 | 180 |
Test | 测试(自我测试,修改代码,提交修改) | 120 | 180 |
Reporting | 报告 | 180 | 120 |
Test Repor | 测试报告 | 60 | 60 |
Size Measurement | 计算工作量 | 90 | 60 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 90 | 60 |
合计 | 1900 | 1820 |
3.解题思路
看到这个题目的时候我很懵,看完大佬写完的之后我就更加懵,不晓得应该从何下手,然后我就去了解了一下数独,刚开始分析时,我认为结合宫格的行、列和每个小宫中的数字信息应该就能确定出来填空格要填入什么数字,而且题目也说了输入仅保证只有一个解,所以我认为在遍历完一遍整个数独之后应该至少能填入一个空,而当填了一个空之后,我们已知的信息就又多了,再多遍历几遍应该就能填完整个数独。但就是有时候并不是遍历完一遍数独之后一定能填入一个空,因为有时候多个待填入的空里都存在着多种可能,所以先把仅根据行列宫就能唯一确定的空先填入,如果最后成功填出整个数独,说明我们就不用进行深度优先搜索;如果最后不能成功填出整个数独,则说明我们要采用深度优先搜索策略,但此时因为我们已经或多或少地填了一些空格,那样就可以减少深搜的时间了。
4.设计实现过程
在设计实现时,因为我发现3-9宫这7个宫格有些宫格具有共性,而有些具有特性,所以我认为可以将这7个宫格分为三类:第一类,3、5、7阶宫格,因为这些宫格不需要考虑宫的信息;第二类,4、9阶宫格,这些宫格虽然要考虑宫的信息,但是小宫的形状是规则的;第三类,6、8阶宫格,每个小宫的形状不规则。但是,这样分类可能导致我写的模块有点多,应该也可以把他们综合起来考虑,从而使整个程序看起来更精简。以下是我程序中主要的函数模块:
1.void sudok1(int m, int count);//参数m为宫格的阶数,count为待填入的空格总数;
功能:sudok1函数的功能是先把阶数为3、5、7的数独中仅根据行列信息就能唯一确定的数字填入
2.void sudok2(int m, int count);//参数m为宫格的阶数,count为待填入的空格总数;
功能:sudok2函数的功能是先把阶数为4、9的数独中仅根据行、列、小宫的信息就能唯一确定的数字填入
3.void sudok3(int m, int count); //参数m为宫格的阶数,count为待填入的空格总数;
功能:sudok3函数的功能是先把阶数为6、8的数独中仅根据行、列、小宫的信息就能唯一确定的数字填入
4.int dfs(int n, int m);//深搜函数是这个程序的核心部分,这里先把数独的每个位置从1-n*n编号,n的初值为一,即数独最左上的位置;参数m代表数独的阶数
功能:深度优先搜索函数,对于数独中每个位置为0的格,从1-m(m为阶数)这m个数中先检查哪个数能填入数独,若能填入则填入,当把整个数独的每个空位都成功填入一次后,说明我们解出了这个数独,于是返回;如果这m个数中没有一个满足要求,则回溯,并将填入的数字置0。
5.int check1(int x, int y, int m, int num);//x为试填的空格的横坐标,y为试填的空格的纵坐标,m为宫格的阶数,num代表试图填入的数
功能:check1函数用于检查试填入阶数为3、5、7宫格的数字的合法性
6.int check2(int x, int y, int m, int num);//参数信息同上
功能:check2函数用于检查试填入阶数为4、9宫格的数字的合法性
7.int check3(int x, int y, int m, int num);//参数信息同上
功能:check3函数用于检查试填入阶数为6、8宫格的数字的合法性
8.子函数间的关系流程图如下:
5.该进程序性能
目前在程序性能改进上还没有过多的想法,现有的解决方法我只能想到深度优先搜索策略,如果说要朝哪些方向优化的话,我觉得可以考虑一下改进深度优先搜索所选取第一个空格的位置,可能位置选取的好的话,就可以更快地解出数独,减少回溯的次数。同时,对于有多个解的数独,如何把每一个解都罗列出来,这应该也是改进的一个方向。以下是一些性能分析的截图:
6.代码说明
1.未采用深度优先搜索策略,仅根据行列宫信息来确定所要填入的数字的代码:
先测试5宫格:
其实这个代码在测试部分数独时是能给出正确结果的,但是在测试7宫格时:
命令行就直接卡死了。output.txt也没有输出,说明程序陷入了死循环,因此,对于某些数独,是有必要采用深度优先搜索策略的。
2.采用深度优先搜索策略,并结合第一个失败代码的测试用例:
3宫格(左边为input.txt,中间为output.txt,右边为答案文本):
4宫格:
5宫格:
6宫格:
7宫格:
8宫格:
9宫格:
7.心路历程与收获
这次编程对我来说有点难,我是一个很怕麻烦的人,东西一多一复杂就忍不住放弃,一直逃避,但是这次让我对github和Visual Studio Community 2019的使用更加熟练,之前也做过性能分析跟动态检查,但是对于单元测试真的是有点迷茫,不晓得应该怎么做。总的来说还是有进步,这次告诉我只要去做,一步一步就会把看起来很难的事情变得很简单。
8.自我评价