代码地址
GitHub:https://github.com/JiuSiZhang/021700827
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(小时) | 实际耗时(小时) |
---|---|---|---|
Planning | 计划 | 1h | 0.5h |
Estimate | 估计这个任务需要多少时间 | 15h | 12.5h |
Development | 开发 | 1h | 1h |
Analysis | 需求分析 (包括学习新技术) | 3h | 2h |
Design Spec | 生成设计文档 | 1h | 0.5h |
Design Review | 设计复审 | 1h | 0.5h |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 1h | 0.5h |
Design | 具体设计 | 1h | 1h |
Coding | 具体编码 | 1h | 1h |
Code Review | 代码复审 | 1h | 1h |
Test | 测试(自我测试,修改代码,提交修改) | 1h | 1h |
Reporting | 报告 | 1h | 1h |
Test Repor | 测试报告 | 1h | 1h |
Size Measurement | 计算工作量 | 0.5h | 0.5h |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 0.5h | 1h |
合计 | 15h | 12.5h |
解题思路
这个题目其实很简单,本质就是搜索+回溯,我们只要写一个dfs函数和check函数就应该可以完成了,比较麻烦的可能是环境方面的设置和读入,话不多说,先上代码,然后一一解释。
dfs函数
基本的dfs函数,判断当前空有没用被填过,如有,则继续向下搜索,否则开始填数并进行验证记得回溯。
void dfs(int x)//dfs函数 递归填数 { if (flag)//如果已经完成 直接返回 { return; } if (x == m * m)//已经找完 { output(); flag = 1; return; } int r = x / m;//行 int c = x % m;//列 if (!s[r][c])//没填过就填这个空 { for (int i = 1; i <= m; i++) { if (check(x, i)) { s[r][c] = i; dfs(x + 1); s[r][c] = 0;//回溯 } } } else//已经有数就跳过 { dfs(x + 1); } }
check函数
这个函数的主要作用是check行和列是否合法,并判断是否为4 6 8 9,因为它们需要验证宫。
bool check(int x, int val)//第一个验证函数 验证行与列且 4 6 8 9时需要判断宫 { int r = x / m; int c = x % m; for (int i = 0; i<m; i++)//行 { if (s[r][i] == val) { return 0; } } for (int i = 0; i<m; i++)//列 { if (s[i][c] == val) { return 0; } } if (m == 4)//4*4 { if (check2(x, 2, 2, val)) { return 1; } else { return 0; } } else if (m == 6)//6*6 { if (check2(x, 2, 3, val)) { return 1; } else { return 0; } } else if (m == 8)//8*8 { if (check2(x, 4, 2, val)) { return 1; } else { return 0; } } else if (m == 9)//9*9 { if (check2(x, 3, 3, val)) { return 1; } else { return 0; } } return 1; }
check2函数
这个函数。用来判断小宫内是否合法。
bool check2(int x, int r, int c, int val)//第二个验证函数 判断宫 { int a = x / m; int b = x % m; a = a / r * r;//行 b = b / c * c;//列 for (int i = a; i<a + r; i++) { for (int j = b; j<b + c; j++) { if (s[i][j] == val) { return 0; } } } return 1; }
output函数
输出函数,将结果输出至文件,注意不一定忽略行末空格。
void output()//输出函数 { for (int i = 0; i<m; i++) { for (int j = 0; j<m; j++) { fprintf(fp2, "%d", s[i][j]);//输出至文件 if (j < m - 1) { fprintf(fp2, " "); } } fprintf(fp2, "\n"); } }
main函数
注意读入方式,一开始不知道怎么通过命令行读入参数,后来看了先写的同学的博客的百度后才知道的。argv【2】,argv【4】,argv【6】,argv【8】分别对应m,n,输入文件名,输出文件名,然后我们定义两个FILE变量,通过fopen打开文件,再用fscanf读取数据。输出到文件用fprintf函数。
int main(int argc, char *argv[]) { //std::ios::sync_with_stdio(false); //cin.tie(0); m = atoi(argv[2]);//读取参数 n = atoi(argv[4]); char *inputname = argv[6]; char *outputname= argv[8]; fp1 = fopen(inputname, "r");//打开输入文件 if (fp1 == NULL) { return -1; } fp2 = fopen(outputname, "w");//打开输出文件,清空文件 if (fp2 == NULL) // { return -1; } fclose(fp2); while (n--) { mst(s, 0);//初始化 flag = 0; for (int i = 0; i<m; i++)//输入 { for (int j = 0; j<m; j++) { fscanf(fp1, "%d", &s[i][j]);//文件读入 } } fp2 = fopen(outputname, "a");//打开输出文件 dfs(0); //开始填数 if (n > 0) { fprintf(fp2, "\n");//输出至文件 } fclose(fp2);//关闭输出文件 } fclose(fp1);//关闭输入文件 return 0; }
难点
其实本次的编程并不难,难的应该是一系列没有学过的操作,比如文件操作,vs工程操作,github操作,这些需要自己去网上找资料学习,不过一遍之后的确熟悉了很多。
Code Quality Analysis检查结果
性能分析工具Studio Profiling Tools分析结果
测试结果展示
**3*3**

**4*4**

**5*5**

**6*6**

**7*7**

**8*8**

**9*9**

全家福
收获与心路历程
学到很多东西,以前自己只会打打题目,其他东西都不怎么忙会用,通过这次实验,学到了很多东西,github,vs,文件操作。以及一些项目管理与测试的知识。