软工第二次作业——数独生成器

数独代码点这里

一、阅读《构建之法》前三章

大致浏览了一下第一章,第一章通常只是介绍一下,本书的结构,以及软件工程的概念。

期中我认为比较重要的一点是:软件工程的目标

886329-20170910215929069-873129048.png

第二章主要说的是对代码性能的测试,大概讲了有,单元测试,代码覆盖率。用了一个统计文本文件中最频繁出现的单词数,这个例子很简单,却非常的适合向读者讲述这个问题。

收获最大的一点:不要盲目的“改进”代码,最好在改进之前做一做本章的性能测试,找到花费时间最长的那一部分的函数,对其进行优化会比对排序这样的虽然改进后排序的效率提升,但是对项目的整体并没有太大的影响,从而做了无用功!!

第三章也稍微重点看了一下,本章主要说的是个人的开发流程,作者在里面给读者们用了各种的比喻,把一个软件开发团队,比喻成足球队,把之间的各个流程都进行了相对应的阐述,非常的易于理解。

保存了书中的对个人能力的一张进阶图,非常有帮助!

886329-20170910215936101-1046229374.png

二、 个人PSP

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划2030
· Estimate· 估计这个任务需要多少时间180360
Development开发4040
· Analysis· 需求分析 (包括学习新技术)3025
· Design Spec· 生成设计文档2020
· Design Review· 设计复审 (和同事审核设计文档)1010
· Coding Standard· 代码规范 (为目前的开发制定合适的规范)1520
· Design· 具体设计3060
· Coding· 具体编码3050
· Code Review· 代码复审2030
· Test· 测试(自我测试,修改代码,提交修改)3060
Reporting报告108
· Test Report· 测试报告105
· Size Measurement· 计算工作量180270
· Postmortem & Process Improvement Plan· 事后总结, 并提出过程改进计划2010
合计645988

三、代码作业

本次作业,是随机生成N个已解答完毕的数独棋盘。按照新增加的要求,我的棋盘的左上角是7.

示例结果:

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

解题思路

本体采用回溯法来生成数独棋盘,算法原理来自网上阅读。一开始想到用交叉变换来做,但是发现交叉变化所要做的分治会比较困难,之后网上搜索之后发现,回溯法生成的数独会比较快,也容易产生不同的解

找资料的过程也比较艰难,一开始用百度搜索,但是代码写的都不是很清楚,很难了解到回溯法的使用。最后向同学请教了如何使用谷歌搜索,体验之后才发现有时候英文的搜索会比中文的更加合适。

回溯法介绍(摘自CSDN博客):

回溯法有“通用的解题法”之称。用它可以系统地搜索一个问题的所有解或任一解。回溯法是一个既带有系统性又带有跳跃性的搜索算法。它在包含问题的所有解的解空间树中,按照深度优先的策略,从根节点出发搜索解空间树。算法搜索至解空间树的任一节点时,总是先判断该节点是否肯定不包含问题的解。如果肯定不包含,则跳过对以该节点为根的子树的系统搜索,逐层向其祖先节点回溯。否则,进入该子树,继续按深度优先的策略进行搜索。回溯法在用来求问题的所有解时,要回溯到根,且根节点的所有子树都已被搜索遍才结束。而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可结束。这种以深度优先的方式系统地搜索问题的解算法称为回溯法,它适用于解一些组合数较大的问题。

代码设计

主要有以下几个函数:

  • addelement 向数组中加入元素
  • recoverElement 回溯查找函数
  • Init 初始化数组
  • F——Best 找到最优的解
  • check_resultShudu 检测数独代码
  • Solve 解数独,采用递归调用回溯

代码说明

关键代码
solveSHudu 判断是否需要回溯,填完一个数字之后,递归进行此操作

bool SolveShudu()
{
    int row,column;
    if(!F_Best(row,column))
        return true;
    for(int i=1;i<10;++i)
    {
        if(!candidate[row][column].test(i))
            continue;
        AddElement(row,column,i);
        if(SolveShudu())
        {
            if(currentIndex==80 && check_resultShudu())
            {
                cout<<endl<<"Result:"<<++resultNum<<endl;
                printResult();
                if(resultNum>=maxNum)
                    return false;
            }
        }
        else
            return false;
        RecoverElement(row,column,i);    
    }
    return true;
}

代码的运行结果图

  • 分别输入纯数字,非纯数字的运行结果

886329-20170910220125022-1766079118.png

正确输入的结果:
886329-20170910220236241-111535760.png

错误输入的结果:
886329-20170910220242366-1209305374.png

除了以上的运行结果,最后测试了1000组,一万组的数据,都能够正常的运行。

性能分析:

CPU利用率

  • 生成100个数独的cpu利用率
    886329-20170910215956788-753911964.png

  • 生成1000个数独的cpu利用率
    886329-20170910220048163-872960377.png

四、中途遇到的困难

1. 读取命令行参数。

这个问题一开始没有注意到,到了最后一天才知道,不使用控制台进行输入,而是直接用控制台运行带命令行参数的方法来执行。一开始并不知道如何增加命令行参数,最后向同学请教了一下,告诉我要去搜索一下argv argc,我新建了一个小的本地测试项目,花了大约一个小时的时间掌握了读取命令行参数

2. git push 没有把BIN文件夹的exe文件提交上去。

这个问题是在最后写博客贴代码项目的时候发现的,bin文件夹里面有两个文件,一个exe。一个txt,但是之后txt提交上去了,这点让人匪夷所思。多次git重复操作之后发现并没有上传成功。最后通过网页端,直接拖拽上传,把exe文件上传到github上面。

3. 识别非法输入。

一开始识别非法输入,是采取网上的现成代码isnum,对纯数字,纯字母的效果比较好,但是,测到一组混合数字字母的字符串的时候如:123afa,会把这个非纯数字当成123,最后过段放弃使用这个代码。

** 用最基本的遍历判断是否是非法字符**,最后通过基本的遍历,然后通过math函数中的atoi函数把字符串数组转换为数值。

4.文件输入输出

一开是没有用vs敲,先用了以前的dev编译环境来编程。一开始用的是freopen来写入文件,最后发现vs运行调试的时候报错了,要我使用更加安全的freopen_s函数来写入文件。这个的网上教程也是写的非常的生涩,最后找了同学支招,叫我去网上搜索ofstream文件输出流,把文件定向输出到txt中。

转载于:https://www.cnblogs.com/kumaxiong/p/7502550.html

数独算法说明:用三个二维数组记录数独每个点的状态,SD(i, j)显示数值,也是真实数值(1到9)。ST(i, j)状态,1可由用户输入,2是题目给定的,不能改。SY(i, j)这符串,记录每个点中可能的值。 1、在进行自动计算时,只计算ST(i, j)为1的点,首先将所有状态为1的点的SY(i, j)值全部设为"123456789",SD(i, j)值全部设为0 2、逐点扫描,找到一个点,然后将该点所在的行、列、区域中已存在的SD(x, y)值从SY(i, j)中删除,因为数独规则是一个数值,在行、列、区域都不重复。 3、经第二步处理后,SY(i, j)为空,说明题目错误,SY(i, j)值为一位数字,就说明该点的值是唯一的,可以确定了。 4、剩余的SY(i, j)值最少也是二个数字的,或更多位数。随机从这些两位数的SY(i, j)中选取一个点。取其中的一位确定为该点的值后,重复第2步。如果错误遇错,则重复执行第4步。直到所有点都被确定。 注意:第2步是需要多次重复执行的,所有可用递归函数完成。如果执行结果出现错误(某数出现重复,或某点无值),需要对该过程所执行的所有操作进行回退。 第4步也是需要重复执行的。本和序用Goto跳转方式实现多次执行。 简单的数独,要么所有的点都具有独一值,第1步执行完成后,就已全部完成。或者具有多个解,随意猜测一个二位数的SY(i, j)的值都能成功。 难的数独,是可唯一确定的点很少,大部分点都有两种或多种可能的值,但最终正确答案只有一种或很少种解。 软件在自动计算过程中,具有很大的偶然性,对于骨灰级的数独题目在计算过程中,时间短的可能不到1秒就能完成,长的可能要几分钟,需要将各种可能性都测试一遍才有结果。 只要题目正确,多计算几次就能得到答案。 程序只处理有两种可能值的情况,对只存在三种可能值的情况未进一步处理,该情况非常极端了。 软件中包含网上下载的200个数独题目。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值