第一次个人编程作业
Github仓库地址https://github.com/JoekrLSJ/031702444
1.PSP表格
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 |
2.解题过程
(1)解题思路
读完题目,第一个想法就是DFS+回溯,总结了一下宫格的特征,发现可以分成两类,一类是有宫的(四六八九宫格),一类是无宫的,即只要判断行列是否冲突(三五七宫格)。题目说是唯一解,所以每次只要填入的是没有冲突的数字,最后能全部填完,就是答案。
(2)程序设计流程图
(3)代码实现
Soduku.cpp 1.0
要点说明
这是最初的版本,先从简单的三五七宫格入手,只要设置行列标记,位置不冲突即可填入,填不完回溯,最后填完就是答案。
设置标记
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+回溯函数
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)性能分析
3.回顾总结
这次题目难度不是很难,主要的时间都花在了熟悉VS 2017的使用,学习如何创建项目,初步学习使用性能分析工具,现在还不是很熟练,后面要熟练掌握。这次还学习了PSP流程,顺便复习了一下int main(int argc,int *argv[])的使用方法。最后熟悉了在Github上面管理代码的方法和流程。