• 软件工程实践2019第三次作业


    GitHub项目地址:

    我的github项目链接:https://github.com/54zhazhahui/131700114

    需求

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

    百度百科简介:

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

    具体任务:

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

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

    PSP表格

    PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划 10分钟 5分钟
    Estimate 估计这个任务需要多少时间 36小时 48小时
    Development 开发 4小时 6小时
    Analysis 需求分析 (包括学习新技术) 2小时 6小时
    Design Spec 生成设计文档 2小时 4小时
    Design Review 设计复审 2小时 1小时
    Coding Standard 代码规范 (为目前的开发制定合适的规范) 1小时 4小时
    Design 具体设计 1小时 1小时
    Coding 具体编码 2小时 1小时
    Code Review 代码复审 2小时 30分钟
    Test 测试(自我测试,修改代码,提交修改) 2小时 8小时
    Reporting 报告 1小时 1小时
    Test Repor 测试报告 30分钟 10分钟
    Size Measurement 计算工作量 10分钟 20分钟
    Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 30分钟 45分钟
    合计 19.2小时 33.2小时
    # 解题思路 看完题目要求之后,我就自己动手画了了一个九宫格。在做题目的过程中,我慢慢体会到解题的思路。基本上就是,排查一个空可能填的数,当只剩下一种可能的时候就可以填了。但是有时候可能有两种或者更多的可能值,这就需要我们去试探了。因为题目比较简单,思路也很快就出来了。用正常的搜索+递归,就能把题目要求的唯一解(标准)数独算出来。比较难的就需要我们去试探了。听说有道史上最难的数独,只有最聪明的人才能解出来,希望我的程序可以算出来。 # 源代码 先看一下主函数吧。这个文件输入输出我整整搞了两天,最后发现两个问题。一个是vs2017建立项目的时候,应该选择建立Windows控制台应用程序。还有一个问题就是input.txt和output.txt写成input.txt.txt和output.txt.txt。讲真的,我自闭了,心态被搞崩了。看了好多资料,用了无数的方法都不行。最后可以实现的那一刻,心里舒服了好多。 **主函数** ``` int main(int argc, char** argv) { int i, j; ifstream ifp; ofstream ofp; m = atoi(argv[2]);//宫阶数 n = atoi(argv[4]);//盘面数 choosemn(); ifp.open(argv[6]); if (!ifp.is_open())//判断文件是否成功打开 cout << "文件打开失败" << endl; ofp.open(argv[8]); if (!ofp.is_open()) cout << "文件打开失败" << endl; while (n > 0) { resetmay(); for (i = 0; i < m; i++)//输入数独盘面 { for (j = 0; j < m; j++) { ifp >> a[i][j].num; } } inputsign(); scansign();
    	for (i = 0; i < m; i++)//输出解出的数独
    	{
    		for (j = 0; j < m; j++)
    		{
    			if (j < (m - 1))
    				ofp << a[i][j].num << " ";
    			else
    				ofp << a[i][j].num;
    		}
    		ofp << endl;
    	}
    	ofp << endl;
    	n--;
    }
    return 0;
    

    }

    **结构体定义数据**
    

    struct number //每个数的结构体 sa
    {
    int sign;//定义一个标记,表示这个数还有几种可能的取值
    int maybe[9] = { 1,2,3,4,5,6,7,8,9 };//定义num的可能取值
    int num;//定义num的确定值
    }a[9][9];

    ### 核心代码
    核心代码是两个函数,一个**唯一值函数**,一个**排查函数**。
    
     **唯一值函数**
    

    void onlyone(int i, int j)//这个函数是把唯一解求出来;
    {
    for (int k = 0; k < line; k++) //唯一解在maybe里面
    {
    if (a[i][j].maybe[k] != 0)
    {
    a[i][j].num = a[i][j].maybe[k];
    a[i][j].maybe[k] = 0;
    a[i][j].sign = 0;
    del(i, j);
    break;
    }
    }
    }

    
    **排查函数**
    

    void deletehl(int i, int j)
    {
    for (int k = 0; k < line; k++)//把同一行的sign减一,把maybe的可能取值变零
    {
    if (a[i][k].maybe[a[i][j].num - 1] != 0)//如果不等0,说明还没去掉这个可能;
    //等0的话,说明前面已经去掉了,sign不用再减一了;
    {
    a[i][k].maybe[a[i][j].num - 1] = 0;
    a[i][k].sign--;
    if (a[i][k].sign == 1)
    {
    onlyone(i, k);
    }
    }//把同一行的相同可能值删掉

    	if (a[k][j].maybe[a[i][j].num - 1] != 0)
    	{
    		a[k][j].maybe[a[i][j].num - 1] = 0;
    		a[k][j].sign--;
    		if (a[k][j].sign == 1)
    		{
    			onlyone(k, j);
    		}
    	}//把同一列的相同可能值删掉 
    }
    

    }

    void deletegong(int i, int j)
    {
    //宫的首地址计算 //x,y;这个宫的首个数的地址为a[x][y] ;
    int x, y;
    x = (i / gongrow) * gongrow;
    y = (j / gongline) * gongline;
    for (int gi = 0; gi < gongrow; gi++)
    for (int gj = 0; gj < gongline; gj++)//把同一宫的sign减一,把maybe【num】的取值变零
    {
    if (a[gi + x][gj + y].maybe[a[i][j].num - 1] != 0)
    {
    a[gi + x][gj + y].maybe[a[i][j].num - 1] = 0;
    a[gi + x][gj + y].sign--;
    if (a[gi + x][gj + y].sign == 1)
    {
    onlyone(gi + x, gj + y);
    }
    }
    }
    }

    唯一值函数就是当一个空的可能性只有一种的时候,就可以填入了。
    排查函数就是把同一列或同一行或同一宫的,已存在的值的可能性排除掉。
    ### 数据测试
    下面是5和6宫格的数据测试结果
    ![](https://img2018.cnblogs.com/blog/1797348/201909/1797348-20190925220600589-545168212.png)
    ![](https://img2018.cnblogs.com/blog/1797348/201909/1797348-20190925220640289-1100503425.png)
    ### 性能分析
    ![](https://img2018.cnblogs.com/blog/1797348/201909/1797348-20190925223552849-1785591570.png)
    ![](https://img2018.cnblogs.com/blog/1797348/201909/1797348-20190925223640034-1913736679.png)
    ![](https://img2018.cnblogs.com/blog/1797348/201909/1797348-20190925223659569-995779287.png)
    
    
    ###总结
    这次作业花了我很长的时间,但是也是收获满满。比如说学会了在github上传代码,还有vs2017的使用,还有文件输入输出!!!在写作业的过程中遇到了很多困难,很多bug,很多意想不到的问题,当是通过自己的努力,一步步攻克过来,最后成功解决。我觉得这个过程才是最重要的,也是我这次最大的收获。
  • 相关阅读:
    分区范围oracle partition table related operations
    软件应用交委有权力叫停打车软件吗?
    美国竞争对手华为将反击竞争对手:我们不会对它们友好
    类型名称了解typename的双重意义
    全局变量局部变量ScriptCase中的全局变量、局部变量
    方法定义django admin中 外键下拉框添加过滤(只需要显示我所要的过滤结果)
    移动设备恶意软件移动设备恶意软件应用泛滥 安卓成攻击首选
    nbtstat命令详解
    route命令范例
    硬盘MBR全面分析
  • 原文地址:https://www.cnblogs.com/booob/p/11587339.html
Copyright © 2020-2023  润新知