软件工程第三次作业之数独
列表项
标签(空格分隔): 未分类
Github项目地址:https://github.com/jjsgxty/031702510
PSP表格
PSP2.1 | Personal Software Process Stages |
预估耗时(min) | 实际耗时(min) |
---|---|---|---|
Planning | 计划 | 50 | 30 |
Estimate | 估计这个任务需要多少时间 | 50 | 30 |
Development | 开发 | 240 | 300 |
Analysis | 需求分析 (包括学习新技术) |
120 | 180 |
Design Spec | 生成设计文档 | 60 | 30 |
Design Review | 设计复审 | 30 | 20 |
Coding Standard | 代码规范 (为开发制定合适的规范) |
30 | 20 |
Design | 具体设计 | 60 | 60 |
Coding | 具体编码 | 240 | 180 |
Code Review | 代码复审 | 180 | 120 |
Test | 测试 (自我测试,修改,提交修改) |
180 | 180 |
Reporting | 报告 | 60 | 60 |
Test Report | 测试报告 | 20 | 20 |
Size Measurement | 计算工作量 | 10 | 10 |
Postmortem & Process< | 事后总结, 并提出过程改进计划 | 60 | 60 |
合计 | 1390 | 1300 |
解题过程
刚开始看到作业的时候,想到可以用DFS递归来实现,作业要求是3~9宫格的实现,我想先完成九宫格的话,其他宫格再改一改就可以了,然后我就开始了九宫格的代码。
1.用深搜构造数独,分别判断每个格子中填入的数字是否正确,如果当前格子不为空就跳过
2.判断填入的数是否正确时,先判断横列,再判断纵列,最后判断每个小宫格
3.全部都符合后,退出递归
完成了九宫格的实现后,我发现麻烦的是cmd命令行参数,刚开始真的很懵,命令行参数不会,文件流也不懂,看了c++书中有关文件流输入输出的内容后会使用文件流,但cmd行参数百度了一堆还是不理解什么意思,最后求助了一位同学,才终于大致搞明白
然后就是进行其他宫格的补充,3、5、7宫格比较简单,只需要判断每一行每一列,所以我把4、6、8、9放在了一起,从九宫格到所有宫格的过程中我经常会在一些细节性的地方忘记修改,每次找都找的很烦,还有我在检验一个宫格是否正确输出的时候,会把输入文件错放成其他宫格的输入文件,找了半天错误原来是文件问题。唉,还是希望自己以后能细心一些吧┭┮﹏┭┮
一共有三个函数 check函数用来判断一个数填入格子中是否符合要求,DFS函数深搜构造数独,还有主函数
Check 函数
//判断shu填入n时是否满足条件
bool Check(int n, int shu)
{
//判断n所在横列是否合法
for (int i = 0; i < siz; i++)
{
int j = n / siz; // j为n竖坐标
if (num[j][i] == shu) return false;
}
//判断n所在竖列是否合法
for (int i = 0; i < siz; i++)
{
int j = n % siz; //j为n横坐标
if (num[i][j] == shu) return false;
}
if (siz == 4 || siz == 6 || siz == 8 || siz == 9)
{
int a, b; //a为每个小宫格中横向的格子数,b为纵向格子数
switch (siz)
{
case 4:
a = 2, b = 2;
break;
case 6:
a = 3, b = 2;
break;
case 8:
a = 2, b = 4;
break;
case 9:
a = 3, b = 3;
break;
}
int x = n / siz / b * b; //x为n所在的小宫格左顶点竖坐标
int y = n % siz / a * a; //y为n所在的小宫格左顶点横坐标
//判断n所在的小宫格是否合法
for (int i = x; i < x + b; i++)
{
for (int j = y; j < y + a; j++)
{
if (num[i][j] == shu) return false;
}
}
}
return true; //都合法,返回正确
}
DFS函数
//深搜构造数独
int DFS(int n)
{
int amount = 0;
switch (siz)
{
case 3:
amount = 8;
break;
case 4:
amount = 15;
break;
case 5:
amount = 24;
break;
case 6:
amount = 35;
break;
case 7:
amount = 48;
break;
case 8:
amount = 63;
break;
case 9:
amount = 80;
break;
}
//所有的都符合,退出递归
if (n > amount)
{
sign = true;
return 0;
}
//当前位不为空时跳过
if (num[n / siz][n % siz] != 0)
{
DFS(n + 1);
}
else
{
//否则对当前位进行枚举测试
for (int i = 1; i <= siz; i++)
{
//满足条件时填入数字
if (Check(n, i) == true)
{
num[n / siz][n % siz] = i;
DFS(n + 1); // 继续搜索
//返回时如果构造成功,则直接退出
if (sign == true) {
return 0;
}
//如果构造不成功,还原当前位
num[n / siz][n % siz] = 0;
}
}
}
return 0; //此处不加会有警告
}
主函数
int main(int argc, char* argv[])
{
int k;
char* in; //输入文件
char* out; //输出文件
int time; //盘面数目
siz = atoi(argv[2]); //atoi (ascii to integer)是把字符串转换成整形数的一个函数
//头文件为 #include
time = atoi(argv[4]);
in = argv[6];
ifstream infile(in);
out = argv[8];
ofstream outfile(out);
for (k = 0; k < time; k++) {
char temp[10][10] = { 0 };
int l = 0;
for (int i = siz * k + k; i < siz * k + k + siz; i++)
{
for (int j = 0; j < siz; j++)
{
infile >> temp[i][j];
num[l][j] = temp[i][j] - '0'; // 两个字符相减就是ASCII码之间的减法操作
}
l++;
}
cout << "\n";
sign = false; //此处注意一定要加!!!
DFS(0);
for (int i = 0; i < siz; i++)
{
for (int j = 0; j < siz; j++)
{
cout << num[i][j] << " ";
}
cout << "\n";
}
cout << "\n";
ofstream outfile;
outfile.open("output.txt", ios::app); //以后继方式打开文件以便继续写
for (int i = 0; i < siz; i++) {
for (int j = 0; j < siz; j++) {
outfile << num[i][j] << " ";
}
outfile << endl;
}
outfile << "\n";
outfile.close();
}
}
测试结果
质量分析 消除警告
因为之前用的Devc++,代码没有问题,然后换到vs上面就报错,说我设置的一个变量size不明确,百度后发现,可能和引用的头文件中标准库的某个变量或函数名字冲突了,然后把size改成了siz,还有一个警告是说DFS返回路径不明确,我把DFS函数里的 return 0 加上后就消除了
性能分析
心路历程与收获
这次作业让我学到了很多,比如GitHub的文件上传,使用Github来管理源代码和测试用例,vs各种报错和警告的解决办法(vs真的把我搞到吐血,为啥这么难用!!!)
个人的一点感概吧,最近几天真的是经历了各种从开心到自闭,再开心再自闭的过程,每次某一个部分成功完成就很开心,但紧接着又会有新的问题出现,然后各种不懂,各种疯狂百度,各种问同学,真的感谢给了我帮助的同学们,做成这样我也真的真的尽力了,还是自己能力太差了,以后会努力的