一、项目地址
代码托管在了GitHub上,附上链接如下:二、PSP
PSP2.1 | Personal Software Process Stages | 预计耗时(min) | 实际耗时(min) |
---|---|---|---|
Planing | 计划 | ||
·Estimate | ·估计这个任务需要多少时间 | ||
Development | 开发 | ||
·Analysis | ·需求分析(包括学习新技术) | 120 | |
·Design Spec | ·生成设计文档 | 60 | |
·Design Review | 设计复审(和同事审核设计文档) | 30 | |
·Coding Standard | ·代码规范(为目前的开发制定合适的规范) | 60 | |
·Design | ·具体设计 | 120 | |
·Coding | ·具体编码 | 1080 | |
·Coding Review | ·代码复审 | 60 | |
·Test | 测试(自我测试,修改代码,提交测试) | 300 | |
Reporting | 报告 | 60 | |
·Test Report | ·测试报告 | 60 | |
·Size Measurement | ·计算工作量 | 60 | |
·Postmortem & Process Improvement Plan | ·时候总结,并提出过程改进计划 | 60 | |
合计 |
三、需求分析
生成终局
输入参数:sudoku.exe -c 20(生成数独终局的数目)
a. 生成指定数量的数独终局
b. 能处理非法参数
c. 左上角第一个数固定(9+7)%9+1=8
d. 输入范围限制在1~1000,要求在60s内给出结果
e. 结果输出到文件sudoku.txt中并要求可被覆盖
求解数独
输入参数sudoku.exe -s absolute_path_puzzlefile
a. 从指定文件中读取数据,并将结果输出到指定文件中
b. 保证文件中数独格式正确
c. 结果的格式要与生成终局的格式相同
四、解题思路描述
项目包括生成指定个数的数独终局以及求解给定的数独终局,因此要弄懂数独生成算法以及求解数独的算法。首先想到的解决办法就是回溯法,对单个数字进行填充,如果的得到的结果不满足条件的话,我们就回溯到上一层,知道求出正解。在搜索引擎输入求解数独可以得知Dancing Links算法是求解数独常用的算法,算法原理比较容易理解,它实际上是一种数据结构(交叉十字循环双向链)。由于解决精确覆盖问题的X算法中需要频繁用到移除、恢复操作,而在这种结构下,进行这两种操作的效率极高。跳跃的舞者,舞蹈链算法(Dancing Links)------求解精确覆盖问题
五、设计实现过程
首先分析出程序流程如下:
列出需要的函数如下:
extern int Read(char str[]); //读取参数并判断参数是否合法
extern int Random_Init(int Num[]); //随机初始化第一行
extern int Judge_Sudoku(int s, int x, int y, int num); //判断数独终局知否合法
extern int Fill_Sudoku(int s, int x, int y); //填充数独
extern int Creat_Sudoku(int Sodoku_Num); //创建数独终局
extern int Solve_Sudoku(char File[]); //解数独残局
五、性能改进
对于第一个可执行的版本,对其进行性能测评,结果如下图所示:
可见函数输出占据了大量时间,于是我将输出改为putchar之后,大量减少了输出时间。
六、代码说明
Fill_Sudoku这一部分函数在很多地方都有调用,将此部分代码拎出来作为重点。
int Fill_Sudoku(int s, int x, int y) //填充函数
{
int Trace_back = Board[s][x][y];
int next_x = x + (y + 1) / 9; //定义下一方格横坐标
int next_y = (y + 1) % 9; //定义下一方格坐标
if (x > 8)
return 1;
if (Board[s][x][y])
{
if (Fill_Sudoku(s, next_x, next_y))
return 1;
}
else
{
int i;
for (i = 0; i < 9; i++) //判断合法性
{
int Try_Num = Try_List[i];
if (Judge_Sudoku(s, x, y, Try_Num))
{
Board[s][x][y] = Try_Num;
if (Fill_Sudoku(s, next_x, next_y))
return 1;
}
}
}
Board[s][x][y] = Trace_back;
return 0;
}