软件工程实践2019第三次做业

软件工程实践2019第三次做业

个人GitHub MrHe-Huskyios

PSP表格:

其实我看到题目首先想到的并非怎么去完成,而是想起了高中和先后左右桌互相传看《意林》的时间,在看完大部分的文章后,附录的数独题便成了最后的乐趣点,虽然不多有人可以彻底解出,但你们还都是都乐在其中。而后想起个人Ubuntu虚拟机上正好有个自带的数独游戏,因而就久违地玩了一把...c++

emmmm....虽然是最基础的数独,但解出的时间并不理想,并且还浪费40多分钟的打代码时间(>_<)git

解题思路:

我是从传统的9阶入手解题,以后再向低阶扩展(以后扩写的过程感受也比较轻松)github

较为机械性的解数独仍是得用到排除法,排除掉全部不可能的取值后惟一肯定一个数填入,以后再进行递归直到解出全部的能肯定的值为止。由此咱们创建一个类,它须要作到:数组

<1> 能储存本元素所剩的全部可能取值
<2> 可以根据同行、列、块进行可能取值排除
<3> 进行自我检查,若自身的值可以肯定则调用同行、列、块的元素排除掉新肯定的元素并自我检查(递归)可否肯定值。函数

类定义:

class element {
public:
     int num;                                //值,未定则为0
     int row_num;                            //行号
     int column_num;                         //列号
     int block_num;                          //宮号
     int possible_num[10];                   //可能取值(possible_num[0]为是否肯定,1:不定,0:肯定,1~9分别对应9个数,0表明不可能,1可能)
     int rm_row(int i, int j, element ele[][10], int m);            //根据行进行可能取值排除
     int rm_column(int i, int j, element ele[][10], int m);         //根据列进行可能取值排除
     int rm_block(int i, int j, element ele[][10], int m);          //根据宫进行可能取值排除
     int set(int rnum, int cnum, int number, int m);                //第一次设定(初始化对象数组)
     int selfcheck(int i, int j, element ele[][10], int m);         //自我检查(若是possible_num的值和为2,把possible_num[0]设为0,num设为值,返回num)
     element() {
          num = 0;
          row_num = 0;
          column_num = 0;
          block_num = 0;
          for (int i = 0; i < 10; i++) possible_num[i] = 1;
     }
};

主要递归函数:

int element::selfcheck(int i, int j, element ele[][10], int m)
{
     int s = 0;
     int t, k;
     int ci, cj;  //c:check,做为行,列,块排除循环参数
     for (t = 0; t <= m; t++) {
          s = s + ele[i][j].possible_num[t];
          if (ele[i][j].possible_num[t] != 0) {  //找最后一个可能的数值k
               k = t;
          }
     }
     if (s == 2) {    //若是可能数值惟一,则对其所在行,列,块排除该数并判断是否能肯定元素值(element::selfcheck()),并设定num
          ele[i][j].num = k;
          ele[i][j].possible_num[0] = 0;//设为0则不可能再进入判断循环
          for (cj = 1; cj <= m; cj++) {
               ele[i][cj].rm_row(i, cj, ele, m);
               ele[i][cj].selfcheck(i, cj, ele, m);//递归
          }
          for (ci = 1; ci <= m; ci++) {
               ele[ci][j].rm_column(ci, j, ele, m);
               ele[ci][j].selfcheck(ci, j, ele, m);
          }
          if (m == 4 || m == 6 || m == 8 || m != 9) {  //4,6,8,9以外的阶数不存在块,不执行块排除
               for (ci = 1; ci <= m; ci++) {
                    for (cj = 1; cj <= m; cj++) {
                         if (ele[i][j].block_num == ele[ci][cj].block_num) {
                              ele[ci][cj].rm_block(ci, cj, ele, m);
                              ele[ci][cj].selfcheck(ci, cj, ele, m);
                         }
                    }
               }
          }
     }
     return 0;
}

以上为主要函数,完整代码见GitHub <MrHe-Husky/031702327/Sudoku.cpp>性能

作到这里完成初步代码后再去玩虚拟机上的数独游戏,速度明显获得了提高(测试

固然,在真正的游戏中这会石锤成做弊行为,而且与追尾黑色高级车同等需道歉三回来求得宽恕,所以不推荐这么作。命令行

完成主体后接着是文件的io,这一部分功能因为以前不多使用到由此十分陌生,在反复翻看书本和看了不少网上的资源后才学会了如何使用命令行参数和文件io方式,写代码过程当中大部分时间都在查资料,顺带感慨本身基础不牢,在这些地方花了很长时间。3d

相较于c不一样,c++进行文件io操做简化了不少;
c语言须要先定义文件指针FILE*,而后再使用open函数来关联指针和文件,以后再使用read()和write()函数来读写,操做完以后再调用close来关闭文件防止出错,较为麻烦;接着来看c++;

/*此段只为样例说明,不可直接执行*/
fstream infile(**char, ios::in);       //指定输入文件流对象infile(能够本身定义名字,ios::in 为操做方式)
fstream outfile(**char, ios::out);     //指定输出文件流对象outfile(能够本身定义名字,ios::out为操做方式)
infile >> 输入对象;
outfile << 输出对象;
/*和普通cin,cout彻底相同的操做,可读入自动识别读入多种数据类型十分方便,头文件<fstream>*/

代码测试:

使用了3~9阶的数据进行测试,如下为检测结果

使用visual studio的性能探测器进行分析

高耗能段:

本为了方便直接在cmd中观察结果的测试代码竟然占了21%的消耗,这点仍是比较出乎意料的。。

《构建之法》读后与本次做业:

首先体会最深的就是按时交付这项,超时直接0分,为了这点熬了两次夜.. 程序可扩展性:从9阶解1个数独往3~9阶解多个数独扩展,同时增长文件io功能,中间有许多变动,不过个人初稿和最后完成版本也只有50行的差距,这或许得归功于使用面向对象方法而且类函数分化,改动时只须要变更一点增长些开关就足够。 注释很重要。 ---END---

相关文章
相关标签/搜索