本次作业的项目地址:Github仓库地址

解题思路

嗯,这次的作业要求是

利用程序随机构造出N个已解答的数独棋盘

刚开始看到的时候可以说是非常茫然的,数独以前虽然玩过,但要用程序来构造那就是完全的另一回事了。一般来说,数独的构造是你根据已有的条件,来判断剩下的空格该填什么数。我自己对这个没什么研究,平时玩的时候挺随心所欲的,这个直接导致我在面对如何用程序来解答的时候毫无头绪。何况这次的要求根本就连条件都没有,要自己凭空造。

凭空,还要随机,只有第一位数是指定的,完全没有方向,所以我就先去网上搜了“如何构建数独”,发现不少前人对此都有研究,我在其中找到了两篇对我来说很有用的,如下:
[http://blog.csdn.net/qq_31558353/article/details/50615760]
[http://blog.csdn.net/xiahn1a/article/details/50852849]

第一篇记录了该如何去解一个数独。这次作业对数独棋盘的要求只有一个,就是左上角第一个数字为(学号后两位相加)%9+1,我的学号末两位为16,也就是说我的矩阵左上角那位应为8
该篇的具体做法大致是说,从第一位开始逐个填数,如果已经有数字了就跳过,如果是空的,就从1开始看能不能填入,判断基准是该位所在的行列和小九宫里是否有跟这个数重复的数,如果没有,就填入这个数,如果有,就跳到下一个数判断能不能填,以此类推。
这种做法很容易遇上某一格一个数都填不进,这个时候就返回到它的前一格,重新走下一个数判断,直到全部填满。
这篇代码的作者非常厉害,仅用了一个n就可以表示数独矩阵每一位的坐标。我因为一开始是用num[i][j]的方法在做,不想改,本身也不能完全照他的走,所以就化用了他的方法。

但即便这样也仅仅是能构建一个以8为头的数独阵,并不能做到随机。这个时候我看到了第二篇博文。这位作者的代码有点繁杂,用到的陌生函数太多我一时看不来,但最开头部分的他的思路给了我非常大的提示。

首先第一行肯定是1~9的一种排列,直接使用shuffle进行随机。

当时看到这句的时候简直是茅塞顿开。数独阵这么多,用第一行随机可不就是能制造大批的不一样的数独嘛!然而很惭愧我不会使用shuffle,而且经过查找发现这个似乎是要在1~9里随机排列。
说到这个就要提老师的那个固定了第一位的要求了,我的首位是8,也就是说剩下8个数得在1~7和9之中随机排列,这就很不一样了,因为我在查“该如何生成一组随机数”的时候,基本上都是要在一个固定范围里随机的,并不能像我希望的那样可以自己指定数字。所以必须要想另外的办法,使我可以随心所欲的用指定的那些数随机排序。

于是我就查找到了第三篇对我来说非常重要的博文!如下:
[http://blog.csdn.net/cxllyg/article/details/7986352]
洗牌算法,我只要自己指定好数组,就可以将[0]位后面的八个数随机排列了。因此我定义了一个数组,内容是{8,1,2,3,4,5,6,7,9},随机的时候将首位除外,剩下的随机排。这也是我第一次认识rand和srand函数。

这些基本就是我的代码的主体构成了。先是在第一个数为8的基础下把1~9随机排序,然后根据已有的第一行推出剩下72个空位应该填什么。

老实说这份作业做得很跌宕起伏,经常是我前一个问题还没理清楚后脚又冒出了另一个问题。命令行输入和查重都是最后一天才发现自己遗漏的,可以说是非常不小心非常不应该的了。何况我最后一天还要返校……命令行还好解决,查重真的就是太困难。一开始做的时候没考虑到,后面想加也很有难度。把全部随机出来的第一排存在同一个数组里,新随机一个就从头开始一个个查有没有重复,数量少还能应付,但多了似乎就会运转不来。之后应该会试着尝试有没有什么更好的方法吧。

设计实现

我一共在头文件里定义了五个函数和一个全局变量,分别是:

bool sign=false;        //用以判断数独阵是否完成
extern int num2[1000000][9];    //定义一个用于查重的数组void firstrank(int num[][9],int n,int sum[][9]);        //随机取数独矩阵第一排的值
bool check(int n,int i,int j,int num[][9]);     //判定数字n能否放入num[i][j]中
int build(int num[][9],int x,int y);        //构建数独矩阵
void change();          //重置sign的值为false
bool diffrent(int a[][9],int b[][9],int n);     //比较a,b两个二维数组是否不相同

Main函数在生成一个数独棋盘之前,首先要先运行firstrank,定好第一行数的排列顺序。
然后要运行diffrent来判断是否有重复。每个新生成的一排随机数都要同num2里存放前几轮随机过的数进行比较。一行一行比,每行一遇到不同就跳转下一行继续比较,如果相同,则判断是否是该行最后一个数,如果是,则说明有完全相同的一行,返回false,如果全部比较完都没有重复,那就返回true。
于是就可以开始运行build,从第二行首位开始构建数独。Build中会用到check来判定这个数能否被放进这个位置里,如果check返回的值为true,就下一位;返回的值若为false,就换一个数继续判定。当所有空位都被填上数字时,build里下一个位置就是第十行第一列,这个时候sign会被置为true,build直接return 0,表明数独已经构建完成,可以等待输出。
函数change是为了重复构建函数而备的,因为sign并非是在main函数里所定义,所以为了能够重复使用,在一个数独开始构建前,要先运行change来确保sign的值确实为false。
输出部分因为涉及写入文本文件,所以我直接放在main函数里了,没有另外定义。
输入部分要求命令行输入,还要判断输入的值是否正确,我设定的是输入错误就会提示“输入错误,请重试”。

代码说明

首先是firstrank的第一行随机排序,代码如下

    int a[9]={8,1,2,3,4,5,6,7,9};       //定义一个数组,第一个数为我的学号末两位16经计算后得出的固定值8int ran,temp;for(int i=2;i<9;i++)    //数组除了第一个数固定为8,其余重组 {ran=rand()%(9-i)+i;temp=a[i-1];a[i-1]=a[ran];a[ran]=temp;        }

check从行,列,小九宫的角度判断是否能够赋值,如下:

    for(a=0;a<9;a++)        //判断第i行是否有与n重复的数字 {if(num[i][a]==n) return false;}for(b=0;b<9;b++)        //判断第j列是否有与n重复的数字 {if(num[b][j]==n) return false;}if(i<3) x=0;        //num[i][j]所在的小九宫左上角的行 else if(i>5) x=6;else x=3;if(j<3) y=0;        //num[i][j]所在的小九宫左上角的列 else if(j>5) y=6;else y=3;for(a=x;a<x+3;a++)      //判断该九宫中是否有与n重复的数字 {for(b=y;b<y+3;b++){if(num[a][b]==n) return false;}}

build从第二行第一列开始为一个一个空位赋值,全部完成后将sign的值标为true,表示数独构造成功。

    if(x==9)        //当全部填满时,数独矩阵完成 {sign=true;return 0;}for(k=1;k<=9;k++)       //从1开始逐个测试是否能放入num[x][y]的位置中 {if(check(k,x,y,num)==true){num[x][y]=k;if(y<8) build(num,x,y+1);       //该位不是这一行的最末位,则继续对其下一位进行置数 else build(num,x+1,0);      //该位已经是这一行的最末位,跳至下一行首位进行置数 if(sign==true)  return 0;       //当数独阵完成时,直接返回 num[x][y]=0;        //如果置数失败,则将这位置0,继续寻找下一个适合的数字 } }

Main函数先要确定随机排序的随机种子和数独最后要输出的文件“sudoku.txt”,然后根据在命令行输入的n来构造数独,如果输入的不属于规定范围内,还要给出错误提示。

n=atoi(argv[argc - 1]);     //命令行输入srand((unsigned)time(NULL));        //随机种子 ofstream outFile;           //输出文件“sudoku.txt” outFile.open("sudoku.txt");if(n<1000000 && n>1)            //判断输入的变量是否为int型 {for(i=0;i<n;i++){change(); int num1[9][9]={0};firstrank(num1,i,num2);         //确定第一行的排序if(diffrent(num1,num2,i)==1)        //判断是否重复{build(num1,1,0);        //开始构建数独for(j=0;j<9;j++)        //输出数独阵到文件“sudoku.txt”中 {for(k=0;k<9;k++){outFile << num1[j][k] << " ";}outFile << endl;}outFile << endl;        //每个数独阵间隔一个空行 }else i=i-1;}}else{cout << "输入错误,请重试。" << endl;        //若变量不为int型,则输出错误提示 }outFile.close(); 

测试运行

截图如下:

性能分析

执行力,泛泛而谈的理解

执行力,按百科上的说法就是“有效利用资源、保质保量达成目标的能力”,也就是说利用现有的条件和知识,通过自己的力量又快又好的完成需要完成的任务。而泛泛而谈,指浮于表面,没有深入研究,一个人讲出来的东西很肤浅毫无思考力,大概就是泛泛而谈了。
按我个人的理解,拿这次作业作比,如果一个人在看到作业后立刻开始思考入手,然后在deadline来临前从容而高水平的完成了它,那就说明他有很强的执行力了。
泛泛而谈嘛,比如说,我上面提及我要换一种更稳妥的方法来查重复,不用事先设一个那么庞大的数组,我说了,却没有去做,并且在想起时不断强调以后会去做,那就是一种很浅薄的表现。
……老实说,我觉得我现在在这里谈论这些,谈论代码的言辞就挺肤浅挺没有见识的……

遇到的困难及解决方法

关于代码思路之中的困难上面已经提过了,现在说的都是一些细节上但是又很恼人的问题。

一个是命令行输入,今天最后了才发现的,int main(int argc ,char *argv[]),乍一看很莫名其妙,好在我舍友为我倾情指点了一下,可以简单进行使用了。
下一个是输出到txt。这个我查了我的一本讲C++的书,按照书上的说法这个创建的文档一般会跟可执行文件在一起。于是我就照着书上的做法直接用了。我比较喜欢在编代码的时候一个一个功能加,所以在建txt之前我都是用cout直接进行输出的。先前的时候是另设了一个output函数来输出,后来为了用outFile又改成直接放在main函数里。
最困难的还是没有办法查重复。我如果要改的话前面firstrank()就要跟着变,时间不足,所以就直接建数组。数组的话必须视线声明大小,[1000000][9]太大了,我一开始在main函数里建的,后来发现没办法执行,又改成全局变量。这下不会报错了,但我自己试了下,我的电脑最多只能随机出5000个左右的数独阵,如果输入6000,就会一直停留在运行,不能结束。我猜测是电脑容量的问题。

PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 10 30
· Estimate · 估计这个任务需要多少时间 10 30
Development 开发 620 890
· Analysis · 需求分析 (包括学习新技术) 60 50
· Design Spec · 生成设计文档 0 0
· Design Review · 设计复审 (和同事审核设计文档) 0 0
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 0
· Design · 具体设计 30 60
· Coding · 具体编码 240 300
· Code Review · 代码复审 30 60
· Test · 测试(自我测试,修改代码,提交修改) 240 420
Reporting 报告 90 90
· Test Report · 测试报告 60 70
· Size Measurement · 计算工作量 10 5
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 20 15
合计 870 1010

转载于:https://www.cnblogs.com/shadeinblue/p/7502404.html

第二次作业——个人项目实战相关推荐

  1. 软件工程实践2017第二次作业-----个人项目实战之数独

    软件工程实践2017第二次作业-----个人项目实战之数独 最后一门考试2017.9.16 github地址:https://github.com/ssuo/shudu 题目地址:http://www ...

  2. 软件工程实践第二次作业——个人项目实战(数独)

    作业链接 1)Github项目地址 2)在开始实现程序之前,在下述PSP表格记录下你估计将在程序的各个模块的开发上耗费的时间 见 8). 3)解题思路描述 拿到题目后,阅读了项目需求,得知这次作业要求 ...

  3. 第二次作业——个人项目实战:数独

    运行环境: windows7 编程IDE: Visual Studio 2013 编程语言: C++ Github地址:biuibiu~ 项目需求 利用程序随机构造出N个已解答的数独棋盘. 输入: 数 ...

  4. 第二次作业— —结对项目

    第二次作业- -结对项目 标签(空格分隔): 需求分析与原型模型设计 结对成员: 031302610 黄志鹏 031302603 陈波 1.样本实例 一个老师的迫切需求----开课报课之繁琐教师开课报 ...

  5. 软工1816 · 第二次作业 - 个人项目

    第二次软工作业 Github提交链接 PSP表格 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 15 45 ...

  6. 2017202110104-高级软件工程第二次作业个人项目之-四则运算生成程序

    GitHub项目地址 https://github.com/Cynnn/Arithmatic PSP2.1表格 PSP2.1 Personal Software Process Stages 预估耗时 ...

  7. java第二部分项目_Java_第二次作业:项目构思与实现

    写在最前: 我我我我我我靠,以后再也不再ddl截止前1小时调试程序了!之前在DDL前1小时修改程序,当我改完后,我想着,再把之前的测试样例跑一遍,如果都对就OK了.就在这时,问题出现了,我之前正确的测 ...

  8. 第二次作业——结对项目之需求分析与原型设计

    031402606 贺翎 031402340 牛妍辉 一.又一个老师的迫切需求--- 选择和分配本科毕设导师之烦恼 首先,让我们一起来看一下客户的现实困扰系负责人下发导师候选名单(excel或word ...

  9. 福大软工1816 · 第二次作业 - 个人项目

    github地址:https://github.com/LEEHONG998 1.PSP表格 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时 ...

最新文章

  1. SAP LSMW 因物料描述里有换行符或者引号导致数据导入失败
  2. java继承的关键字_超级关键字在Java继承中的作用
  3. 详解Java解析XML的四种方法(转载)
  4. C#实现水晶报表绑定数据并实现打印
  5. 【Python】判断字符串 str 是否为空
  6. 【Task5(2天)】模型调参
  7. 思品课如何使用计算机教学课件,小学思品获奖论文巧用多媒体,优化思品课堂教学...
  8. LaTeX:Texlive 2019和TeX studio
  9. 学好前端的 6 点建议,企业需要什么样的Web前端人才?
  10. 2021年中国云应用服务市场趋势报告、技术动态创新及2027年市场预测
  11. centos7 vsftpd默认端口修改
  12. Repeater的ItemCommand事件和ItemCreated事件,高手请跳过~
  13. JBPM工作流框架应用
  14. iPhonexr安兔兔html5测试,iPhone XR安兔兔跑分多少 苹果iPhone Xr安兔兔跑分公布
  15. 在微博投放广告有哪些优势呢?微博广告推广位置介绍!
  16. 【Java程序员面试】直接被SpringBoot干趴?NONONO!拒绝做冤大头!!
  17. SAP 采购申请审批
  18. 主键约束、主键自增约束、唯一约束、非空约束、外键约束
  19. 跑步装备推荐:跑步运动装备清单分享
  20. C# Volo.Abp使用原生sql语句查询

热门文章

  1. 等价类划分方法的应用
  2. Maven实战系列文章目录
  3. linux下添加自动启动项,linux 开机自动启动脚本方法
  4. Openxml: 导出excel 设置 cell的格式
  5. 根据日期时间和随机量生成唯一ID!!
  6. [转发]项目修复-把有麻烦的项目带向成功
  7. Centos7.6 下部署Cobbler
  8. 设计模式(四)OkHttp的责任链模式
  9. memchace监控统计
  10. (转)创建Windows服务(Windows Services)N种方式总结