Github仓库地址https://github.com/JoekrLSJ/031702444node
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 30 |
Estimate | 估计这个任务须要多少时间 | 1440 | 1200 |
Development | 开发 | 180 | 240 |
Analysis | 需求分析 (包括学习新技术) | 60 | 120 |
Design Spec | 生成设计文档 | 60 | 30 |
Design Review | 设计复审 | 120 | 60 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 120 | 60 |
Design | 具体设计 | 60 | 60 |
Coding | 具体编码 | 120 | 180 |
Code Review | 代码复审 | 120 | 60 |
Test | 测试(自我测试,修改代码,提交修改) | 120 | 120 |
Reporting | 报告 | 60 | 30 |
Test Repor | 测试报告 | 120 | 150 |
Size Measurement | 计算工做量 | 60 | 30 |
Postmortem & Process Improvement Plan | 过后总结, 并提出过程改进计划 | 180 | 150 |
合计 | 1440 | 1200 |
读完题目,第一个想法就是DFS+回溯,总结了一下宫格的特征,发现能够分红两类,一类是有宫的(四六八九宫格),一类是无宫的,即只要判断行列是否冲突(三五七宫格)。题目说是惟一解,因此每次只要填入的是没有冲突的数字,最后能所有填完,就是答案。git
Soduku.cpp 1.0github
要点说明编程
这是最初的版本,先从简单的三五七宫格入手,只要设置行列标记,位置不冲突便可填入,填不完回溯,最后填完就是答案。
设置标记函数
int Soduku_map_row[maxn][maxn]; //行标记,未填入为0 int Soduku_map_column[maxn][maxn]; //列标记,未填入为0 int flag; //填完标记
用结构体队列存储待填格子行列位置工具
struct node { int nrow; int ncolumn; } blank_node[maxn*maxn],pos_node[maxn]; //记录未填入宫格的行列坐标
求解方法:DFS+回溯函数post
Soduku_find()性能
调用这个函数计算三五七宫格数独单元测试
void Soduku_find(int now) { if (flag) return; if (now == blank_node_count + 1) { flag = 1; return; } int x = blank_node[now].nrow; int y = blank_node[now].ncolumn; rep(i, 1, n) { if ((!Soduku_map_row[x][i]) && (!Soduku_map_column[y][i])) { Soduku_map_row[x][i] = 1; //行不冲突 Soduku_map_column[y][i] = 1; //列不冲突 Soduku_map[x][y] = i; //这个格子填入i Soduku_find1(now + 1); //填下一个格子 if (flag) return; //填完退出 Soduku_map_row[x][i] = 0; //行标记 Soduku_map_column[y][i] = 0; //列标记 } } }
输入函数 Soduku_input()学习
void Soduku_input() { rep(i, 1, n) { rep(j, 1, n) { cin >> Soduku_map[i][j]; if (Soduku_map[i][j] == 0) { blank_node_count++; blank_node[blank_node_count].nrow = i; blank_node[blank_node_count].ncolumn = j; } else { Soduku_map_row[i][Soduku_map[i][j]] = 1; Soduku_map_column[j][Soduku_map[i][j]] = 1; if (!(n == 3 || n == 5 || n == 7)) { int pos = getpostion(i, j, pos_node[n].nrow, pos_node[n].ncolumn, n); Soduku_positon[pos][Soduku_map[i][j]] = 1; } } } } }
输出函数 Soduku_outputput()
void Soduku_output() { rep(i, 1, n) { rep(j, 1, n) { if (j != n)cout << Soduku_map[i][j] << " "; else cout << Soduku_map[i][j]; } cout << endl; } cout << endl; }
Soduku.cpp 2.0
因为四六八九宫格每种宫格的行列划分的方法不同,因此设计了一个函数输入待填位置的行列坐标和小宫格行列数以及大宫格的边长就能算出当前位置在哪一个宫格。
宫格函数int getpostion(int,int,int,int,int)
int getpostion(int x, int y, int row, int column, int n) { return (x - 1) / row * (n / column) + (y - 1) / column + 1; }
举个例子,在九宫格(5,4)位于第5宫格,(5 - 1)/ 3 *(9 / 3)+ (4 -1)/ 3 +1=5。每一个宫格3行3列,(x - 1)/ row算出在第几行的宫格,乘上每行有(n / cloumn)个宫格,再加上在第几列的宫格上(y - 1) / column + 1,最后就是所在宫格的位置。
加入宫标记
Soduku_positon[maxn][maxn]; //宫标记,未填入为0
增长void Soduku_find2(int)函数,计算四六八九宫格数独。
void Soduku_find2(int now) { if (flag) return; if (now == blank_node_count + 1) { flag = 1; return; } int x = blank_node[now].nrow; int y = blank_node[now].ncolumn; int pos = getpostion(x, y, pos_node[n].nrow, pos_node[n].ncolumn, n); rep(i, 1, n) { if ((!Soduku_map_row[x][i]) && (!Soduku_map_column[y][i]) && (!Soduku_positon[pos][i])) { Soduku_map_row[x][i] = 1; //行不冲突 Soduku_map_column[y][i] = 1; //列不冲突 Soduku_positon[pos][i] = 1; //宫不冲突 Soduku_map[x][y] = i; //这个格子填入i Soduku_find2(now + 1); //填下一个格子 if (flag) return; //填完退出 Soduku_map_row[x][i] = 0; //行标记 Soduku_map_column[y][i] = 0; //列标记 Soduku_positon[pos][i] = 0; //宫标记 } } }
(4)单元测试样例
三宫格
四宫格
五宫格
六宫格
七宫格
八宫格
九宫格
后面简单写了个批处理文件test.bat测试一下输出结果的正确性。
test.bat代码
@echo off title "Black Box Test" for %%i in (3,4,5,6,7,8) do ( echo 当前测试第m%%in5组: echo 5 %%i > input.txt type m%%in5.txt >> input.txt Sudoku fc output.txt m%%in5_answer.txt /W pause >nul del input.txt del output.txt )
若是输入文件output.txt和m3n5answer.txt内容一致答案正确就会显示“找不到相异处”,反之会提示两个文件不同的地方。
(5)异常处理
在编译的时候一直出现C4996的错误没法消除,查了一下是由于freopen和预处理器的问题,经过在预处理器最上方,也就是第一行添加以下代码,便可解决该错误:
#pragma warning(disable:4996)
(6)性能分析
此次题目难度不是很难,主要的时间都花在了熟悉VS 2017的使用,学习如何建立项目,初步学习使用性能分析工具,如今还不是很熟练,后面要熟练掌握。此次还学习了PSP流程,顺便复习了一下int main(int argc,int *argv[])的使用方法。最后熟悉了在Github上面管理代码的方法和流程。