2020软件工程作业03
这个作业属于那个课程 | https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1 |
---|---|
这个作业的要求在哪里 | https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1/homework/10494 |
这个作业的目标 | https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1/homework/10494 |
作业正文 | 如下 |
其他参考文献 | 百度等 |
我的github项目链接:https://github.com/54
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这个工具,以及编程能力的提高,代码的检查等等。