• 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。
    作业正文  此文章
    其他参考文献

     www.baidu.com,知乎

    1、Github项目地址

     https://github.com/hangoveri1/20177666

    2、PSP表格

    PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
    Planning 计划 20 30
    Estimate 估计这个任务需要多少时间 20 20
    Development 开发 800 1200
    Analysis 需求分析 (包括学习新技术) 20 30
    Design Spec 生成设计文档 90 90
    Design Review 设计复审 25 25
    Coding Standard 代码规范 (为目前的开发制定合适的规范) 0 0
    Design 具体设计 60 90
    Coding 具体编码 600 950
    Code Review 代码复审 20 25
    Test 测试(自我测试,修改代码,提交修改) 120 150
    Reporting 报告 120 360
    Test Repor 测试报告 40 60
    Size Measurement 计算工作量 0 0
    Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 90 120
    合计   2005 3150

    3、解题思路

    3.1问题描述

    实现一个命令行程序,不妨称之为Sudoku。

    数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。

    具体任务:

    现在我们想一步一步来,完成从三宫格到九宫格的进阶;完成三宫格和其他博客任务,就算过了初级考核,其他的算升级。具体各阶规则如下:

    三宫格:盘面是3*3。使1-3每个数字在每一行、每一列中都只出现一次,不考虑宫;
    四宫格:盘面是2*2四个宫,每一宫又分为2*2四个小格。使1-4每个数字在每一行、每一列和每一宫中都只出现一次;
    五宫格:盘面是5*5。使1-5每个数字在每一行、每一列中都只出现一次,不考虑宫;
    六宫格:盘面是2*3六个宫,每一宫又分为3*2六个小格。使1-6每个数字在每一行、每一列和每一宫中都只出现一次;
    七宫格:盘面是7*7。使1-7每个数字在每一行、每一列中都只出现一次,不考虑宫;
    八宫格:盘面是4*2八个宫,每一宫又分为2*4八个小格。使1-8每个数字在每一行、每一列和每一宫中都只出现一次;
    九宫格:盘面是3*3九个宫,每一宫又分为3*3九个小格。使1-9每个数字在每一行、每一列和每一宫中都只出现一次;

    3.2理解问题

    该算法题的需求是实现一个称之为Sudoku命令行程序。

    程序要实现利用逻辑和推理,在在数独盘面的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次。

    输入要求输入文件名以命令行参数传入。

    输出要求输出n个程序解出的盘面,每两个盘面间空一行,每个盘面中,每两个小格之间有一个空格。

    3.3思考如何实现

    数独是需要我们去按规则填写数字:同一行同一列不能出现相同数字,非素数阶数还需要满足每个宫内不能有相同数字。

    我查阅了很多资料思考用什么方法去实现,

    第一种想法 —— 蛮力法

    第二种想法 —— DFS

    第三种想法 —— 回溯法

    回溯法思想

    在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。 若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。 而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。

    这些算法我都不怎么了解,然后我决定先去了解分析了数独的填数字规则和要求,在了解了题目的规则以后,我觉得回溯法非常的适合,因为对于生成的数独终局,我们只要按顺序一个一个填数字就好啦,每完成一个数字都检查它的所在行,列和宫是否满足数独规则,若满足就填写下一个数字,否则则回溯,之后就在编写代码的路途上一去不复返了……

    4、设计实现过程

    4.1函数模块的设计

    • 根据本题的解题要求和思考中确定的递归解题思想,应设计以下模块:
      • 主函数模块(数值的输入,合法性判断,试值的判断,试值的检查)
      • 输出文件生成模块

    4.2具体功能函数设计

    • main()函数

      • 接受命令行参数,并进行解析
      • 读取输入的数字矩阵,对当前坐标格子状态和递归状态进行判断(flag的值)
      • 根据矩阵数量尝试填入数值,并且用循环语句进行判断是否填入该数值
      • 验证失败的话就回溯继续填入数值进行判断
    • output函数

      • 对于main函数中的试值判断结果进行输出显示出来
    • check函数

      • 对传入的坐标进行行列和宫进行重复判断和定位
      • 根据是否合法返回布尔值
    • vfprintf函数

      • 根据传入的矩阵数值将该矩阵写入output函数中
    • 简单流程图

    4.3变量设置

    • int str[9][9]
    • int i,j,k,num,flag,count,control,con,cishu

    5、改进思路

    5.1代码静态分析

     我写了两个代码,这是第一个代码的静态检查出现的问题,

    加以改进后还是有问题,我反复查阅资料虽然解决了,但是分析却分析不出来了,我就试一试另外一种方法进行改写,(害,真的太烦人啦)

     

    5.2代码性能优化

     这个main函数里面的东西占CPU时间很多,执行单个工作最多的函数_stdio common _vfprintf独占时间百分比居然有79.57%,而且它只调用了一次就占这么多时间,反观调用次数最多的_checkForDebugge...被调用九次也没占多少时间,所以我应该吧把main方法中的那个循环语句,也就是判断数值的行列写得更加简单些,然后我就开启了很长一段时间的改写,最终结果就是无法进行性能分析……

     

    5.3单元测试

     软件有问题,单元测试不出来……唉

    6、代码的运行出现的错误以及更改(简单描述几个)

    经过不断的更改代码的小错误终于代码可以运行成功并且没有报错:

     运行结果截图:

     

     代码静态检查并且运行的时候出现了这样的问题:

     

     这是因为我发现我那个get的方法出现了异常所以它一直进行处理数据没有停下来过

    7、代码说明#include<stdio.h>#include<conio.h>

    int str[9][9];
    void output();
    int main()
    {
    //定义
    int i,j,k,num,flag=0,count=0;
    int control=0,con=0;
    int cishu=0;
    //输入
    printf("请输入81个数,空位用“0”代替:
    ");
    for(i=0;i<9;i++)
    {
    for(j=0;j<9;j++)
    {
    scanf("%1d",&str[i][j]);
    }
    }
    //处理

    //关键代码由此开始
    while(con==0) { con=1; for(i=0;i<9;i++) { for(j=0;j<9;j++) { if(str[i][j]==0) { ////////////////////////////////////////////////////////////////////////// //试值开始 for(num=1;num<=9;num++) { flag=0; //不同于九格 if(i%3==0&&j%3==0) { if(num!=str[i][j+1]&&num!=str[i][j+2]&&num!=str[i+1][j]&&num!=str[i+1][j+1]&&num!=str[i+1][j+2]&&num!=str[i+2][j]&&num!=str[i+2][j+1]&&num!=str[i+2][j+2]) { flag=1; } } else if(i%3==0&&j%3==1) { if(num!=str[i][j+1]&&num!=str[i][j-1]&&num!=str[i+1][j]&&num!=str[i+1][j+1]&&num!=str[i+1][j-1]&&num!=str[i+2][j]&&num!=str[i+2][j+1]&&num!=str[i+2][j-1]) { flag=1; } } else if(i%3==0&&j%3==2) { if(num!=str[i][j-2]&&num!=str[i][j-1]&&num!=str[i+1][j]&&num!=str[i+1][j-2]&&num!=str[i+1][j-1]&&num!=str[i+2][j]&&num!=str[i+2][j-2]&&num!=str[i+2][j-1]) { flag=1; } } else if(i%3==1&&j%3==0) { if(num!=str[i][j+1]&&num!=str[i][j+2]&&num!=str[i+1][j]&&num!=str[i+1][j+1]&&num!=str[i+1][j+2]&&num!=str[i-1][j]&&num!=str[i-1][j+1]&&num!=str[i-1][j+2]) { flag=1; } } else if(i%3==1&&j%3==1) { if(num!=str[i][j+1]&&num!=str[i][j-1]&&num!=str[i+1][j]&&num!=str[i+1][j+1]&&num!=str[i+1][j-1]&&num!=str[i-1][j]&&num!=str[i-1][j+1]&&num!=str[i-1][j-1]) { flag=1; } } else if(i%3==1&&j%3==2) { if(num!=str[i][j-2]&&num!=str[i][j-1]&&num!=str[i+1][j]&&num!=str[i+1][j-2]&&num!=str[i+1][j-1]&&num!=str[i-1][j]&&num!=str[i-1][j-2]&&num!=str[i-1][j-1]) { flag=1; } } else if(i%3==2&&j%3==0) { if(num!=str[i][j+1]&&num!=str[i][j+2]&&num!=str[i-2][j]&&num!=str[i-2][j+1]&&num!=str[i-2][j+2]&&num!=str[i-1][j]&&num!=str[i-1][j+1]&&num!=str[i-1][j+2]) { flag=1; } } else if(i%3==2&&j%3==1) { if(num!=str[i][j+1]&&num!=str[i][j-1]&&num!=str[i-2][j]&&num!=str[i-2][j+1]&&num!=str[i-2][j-1]&&num!=str[i-1][j]&&num!=str[i-1][j+1]&&num!=str[i-1][j-1]) { flag=1; } } else if(i%3==2&&j%3==2) { if(num!=str[i][j-2]&&num!=str[i][j-1]&&num!=str[i-2][j]&&num!=str[i-2][j-2]&&num!=str[i-2][j-1]&&num!=str[i-1][j]&&num!=str[i-1][j-2]&&num!=str[i-1][j-1]) { flag=1; } } //不同与九格结束 //不同于行列检测 if(flag==1) { //不同于行 for(k=0;k<9;k++) { if(k!=i) if(num==str[k][j]) { control=1; } } //不同于列 if(control==0) for(k=0;k<9;k++) { if(k!=j) if(num==str[i][k]) { control=1; } } //不同于行列结束 }//不同于行列检测结束 if((control==0)&&(flag==1)) { str[i][j]=num; count++; } control=0; }//试值结束 if(count>1) { str[i][j]=0; } count=0; }//if(str[i][j]==0)控制结束 }//每行中每列处理结束 }//每行处理结束 //检测是否全部赋值 for(i=0;i<9;i++) for(j=0;j<9;j++) { if(str[i][j]==0) { con=0; } } //分次输出 printf("第%d次处理",++cishu); output(); }//while(con)结束 //输出 output(); //结束 getch(); }//main结束
    //关键代码到此结束
    void output() { int i,j; printf("答案为: "); for(i=0;i<9;i++) { for(j=0;j<9;j++) { printf(" %d ",str[i][j]); } printf(" "); } }

    8、心历路程与收获

    经过这次作业,我好无力呀,我看了很多网上大牛的代码,(emmmm,啥玩意呀,看不懂啊,上天啊杀了我吧……),然后有些函数得调用还不知道是啥函数,就一个个一个个百度搜索,因为在性能分析那块我的知识有限,他出来的那些图,我不知道如何优化我的代码,就先一步一步试一试修改一下,改着改着我头顶发凉,都报错了,我这……后来运行的时候出现的语法错误呀,就算语法修改成功啦,结果就一直在哪里处理下去,一直循环下去,就不见他停下来过,说实话改怕了,索性就不改了,就那样吧,作业时间也快用完啦,问了一些学这个的朋友(小牛)我也还是没搞明白,然后要给出宫格的升阶,我就直接九宫格吧,那些3,6...啥宫格的我没有弄,路漫漫其修远兮啊……

    这次的作业让我知道我自己还有好多不足的地方,唉,说多了都是泪,也非常感谢我室友的帮助,教了我很多知识,还有帮我去运行我的代码,虽然这次作业没有很好的完成,也就是没有全部完整的完成,但是在以后的时间我要慢慢的完善他,这不完完全全只是一次作业,这是检测我自己的能力的一种活动,不能抱着应付的态度,好好努力坚持下去吧……

    9、 自我评估

    作业头解题思路描述Github项目地址PSP表格估计PSP表格实际代码如何组织关键函数流程图单元测试设计展示关键代码解释思路与注释说明结合构建之法谈感想总分
    2 0.5 2 0.5 0.5 0.2 0.5 0 0.5 0.5 0.2 7.4
  • 相关阅读:
    openGL线s的绘制
    openGL绘制正方形
    openGL的使用步骤
    [归并排序][逆序数]Brainman
    [动态规划]Tak and Cards
    [STL][stack]简单计算器
    [题解]2018湘潭邀请赛
    [数论][组合数学]Iroha and a Grid
    [STL][stack]括号配对问题
    [简单思维题]Sequence(山东省第九届ACM大学生程序设计竞赛E题)
  • 原文地址:https://www.cnblogs.com/leiqing0519/p/12582233.html
Copyright © 2020-2023  润新知