[2017BUAA软工]个人项目

软工个人项目



一、Github项目地址

https://github.com/Lydia-yang/2017BUAA-SoftwareEngineering


二、解题思路

在刚开始拿到题目的时候,关于生成数独终局,我的思路是可以随机生成数然后选择适合的数填满即可得到,后来通过上网查找一些数独生成算法,发现可以通过一定的顺序来减少工作量,比如将1到9个数字依次随机填入3*3的宫格里,或者记录每次每次尝试的数避免重复,还有初始化对角线的3个3*3的宫格,或者依次填入1到9等。最后选定了将1到9个数值依次填入3*3的宫格里这种算法,也就是这篇博客的算法。
将数独分为9小块,将1-9按照一定序列填写1-9小块,比如先将1填入1号小块,再填入2号小块,知道填完9号小块,再填2与1一样,遍历所有数即可得到一个生成数独。
至于解数独,思路与生成数独差不多,也是回溯,但是是对于每一个没有填的位置试所有可能的数字。


三、设计实现过程

实现我的算法,首先,要有一个存储九宫格的二位数组,出于考虑,我创建了一个数独类,这个类里有相应的行列及3*3小块的重复检查,以及插入和删除,由于我解决数独和生产数独用的是不同的方法来插入数字的(一个是确定数字选位置,一个确定位置选数字),所以有两种插入的方法,然后就是打印数独的方法。
在处理命令行中,有判断-c后面接的是否是正整数的函数,同样,生成数独和解数独都有各自的函数,解数独是通过文件读入的,因此也设定了一个处理文件读入函数,在后面优化的过程中,又新增了输出到文件的函数,单元测试主要是将produce和solve这两个函数测试了一遍。下图是函数类之间的关系:

1225050-20170926192854122-2008701352.png


四、性能改进

一开始生成数独时,几分钟都没出结果,后来经过性能分析,如下图:
1225050-20170926180615309-980838318.png


发现是输出占了大多数时间,后来做了优化,将输出结果先输出到一个字符数组里,再全部一起输出,最后的性能分析如下:
1225050-20170926191155700-1410934381.png


五、代码说明

下面这段代码是用来解数独的,其中输入代表的含义为:

  • sudoku sudo, 存储待解的数独
  • int x[], 所有为空位置的x值
  • int y[], 所有为空位置的y值
  • int total, 空位子的总数
  • int & count, 用来记录目前已经填了多少空位子
  • char *str, 字符数组用来储存需要打印的数独
  • int &count_s, 用来标记字符数组的元素个数

对于每一次执行,将这个空位子插入数字,并标记已经试过的数字,最后完成时输出,每次回溯时都清空当前位置。


void solve(sudoku sudo, int x[], int y[],int total, int & count, char *str, int &count_s) {
    int marked[9] = { 0 };//用来标记数字是否已经选过
    int new_count = count;
    while (true) {

        int now = sudo.insert(1, x[new_count], y[new_count], marked);//在空位子插入数字

        if (now < 0) return;
        else marked[now-1] = 1;

        if (new_count == total - 1) {//最后一个
            sudo.printsudoku(str, count_s);//打印数独
            return;
        }
        count = new_count + 1;
        solve(sudo, x, y, total, count, str, count_s);//下一个
        if (count == total - 1) return;
        sudo.del(1, x[new_count], y[new_count]);
    }
    
}



下面这段代码是用来生成数独的,其中输入代表的含义为:

  • int total, 最终需要生成数独的总个数
  • int nums[], 1-9的序列用来规定遍历数的顺序
  • int block_num, 标记当前的3*3的块号
  • int & count_total, 用来标记当前已经生成的数独个数
  • int count_nums, 用来标记当前对于nums的元素位置
  • sudoku s, 当前已经填好一些空的数独
  • char *str, 字符数组用来储存需要打印的数独
  • int &count_s, 用来标记字符数组的元素个数

对于每一次执行,将这个数字插入当前3*3小块空的位置,并标记已经试过的位置,最后完成时输出,每次回溯时都清空当前位置。


void produce(int total, int nums[], int block_num, int & count_total, int count_nums, sudoku s, char *str, int &count_s) {
    int marked[9] = { 0 };//标记已经试过的位置
    int new_block_num, new_count_nums;
    
    while (true) {
        new_block_num = block_num + 1;
        new_count_nums = count_nums;
    
        int now = s.insert(nums[new_count_nums], new_block_num, marked);
    
        if (now <0) return;
        else marked[now] = 1;

        if (new_block_num == 9) {
            if (new_count_nums < 8) {
                new_count_nums=count_nums+1;
                new_block_num = 0;
            }
            else {//填写至最后一个
                count_total++;
                s.printsudoku(str, count_s);//打印数独
                s.del(0, new_block_num, now);
                return;
            }
        }
        produce(total, nums, new_block_num, count_total, new_count_nums, s, str, count_s);
        if (count_total == total) return;
        s.del(0, new_block_num, now);
    }
}


六、PSP

Psppersonal software progress stages预估耗时实际耗时
planning计划2030
estimate估计这个任务需要多少时间1010
development开发480600
analysis需求分析1010
design spec生成设计文档3035
design review设计复审00
coding standard代码规范1015
design具体设计6070
coding具体编码240300
code review代码复审120130
test测试240300
reporting报告2018
test report测试报告2010
size measuring计算工作量53
postmortem & process improvement plan事后总结,提出过程改进计划2020
合计12851551

转载于:https://www.cnblogs.com/lydiayang/p/7597937.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值