1.Github地址 xinz
2.解题思路:
一开始拿到这道题的时候,对数独的概念不是那么清晰。通过题目中百度百科的概念,即被概括成满足以下三个条件的数字范围为1-9的棋盘:(1)每一行不能有重复的数字(2)每一列不能有重复的数字(3)9乘9的大数独盘被划分成9个3乘3的小九宫格,在每个小九宫格内不能有重复数字
按照人脑填数独的思维我们很容易想到“枚举”的方法,即从填第2个数开始递归填写观察是否满足三个条件,依次往下填写输出一个结果棋盘后进行“回溯”。所以这种“暴力的”程序还是比较简单易懂的,通过百度也了解到其他算法,比如交换行列、用随机数生成等等,但都不如枚举来的直接易懂。
•从第二个格子开始,根据数独需要满足的三个条件从1-9枚举填数字,并同时标记该格子内哪些数字试过了
•对剩下的格子进行递归操作
•输出一个结果棋盘后将记录该数字是否存在的数组复原,为下一次试数做准备,进行回溯,重复上述操作
•直到满足所需棋盘个数,结束
途径:百度 + 自己思考 + 同学帮忙
3.设计实现过程
3.1流程图:
3.2设计思路:
对输入的格式进行处理,使其输入格式为“sudoku.exe -c 生成数独个数”,封装在input_check函数中
输出在outfile函数中,当输出所需个数的数独棋盘后结束
枚举试数字的方法(回溯)在sudoku函数中
4.代码说明
int input_check(int argc, char *argv[])
{
if (argc != 3)
{
cout << "invaild input" << endl;
return -1;
}
if (argc == 3 && strcmp(argv[1], "-c") != 0)
{
cout << "please input -c" << endl;
return -1;//如果输入第二个参数不是-c 不输出
}
if (atoi(argv[2]) == 0)
{
cout << "please enter a value greater than 0" << endl;
return -1;//如果输入第三个参数不是数字 不输出
}
return atoi(argv[2]);
}
//用递归生成数独,nrow表示当前行,ncol表示当前列,表示当前正在处理第nrow行第ncol列的格子。
void shudu(int nrow, int ncol, ofstream &savefile)
{
//计算该格子在哪个九宫格中
int nowbox = ((nrow - 1) / 3) * 3 + ((ncol - 1) / 3 + 1);
//对该格子进行1-9的数字尝试,如果nownum==num则说明棋盘已经够了,就不用再进行下去了,循环退出
for (int i = 1; i <= 9 && nownum<num; i++)
{
//如果数值i在该行该列没有出现过,则进行下一步操作
if (row[nrow][ran_num[i]] == 0 && column[ncol][ran_num[i]] == 0 && box[nowbox][ran_num[i]] == 0)//判定数值i在该行该列该九宫格有没有出现过
{
result[nrow][ncol] = ran_num[i];//把数值i填写入最终棋盘
row[nrow][ran_num[i]] = column[ncol][ran_num[i]] = box[nowbox][ran_num[i]] = 1;//记录下i这个值在该行该列和该九宫格出现了
//如果这个格子是最后一个格子了,说明已经找到一个数独棋盘
if (nrow == 9 && ncol == 9)
{
nownum++;//已找到的数独棋盘数量+1
if (nownum == num) outfile(savefile, true);//这个是最后一个棋盘
else outfile(savefile, false);//这不是最后的棋盘
}
//如果这个格子不是最后一个格子,则对下一个格子进行枚举
else
{
if (ncol == 9) shudu(nrow + 1, 1, savefile);//如果这个格子是该行最后一个格子,则换行
else shudu(nrow, ncol + 1, savefile);//如果这个格子不是该行最后一个格子,则处理该行下一个格子
}
row[nrow][ran_num[i]] = column[ncol][ran_num[i]] = box[nowbox][ran_num[i]] = 0;//递归完后复原,为下一个数字的尝试做准备
}
}
}
//把当前的数独棋盘输出到文件,savefile为输出文件流,islast表示当前输出的棋盘是否为最后一个棋盘
void outfile(ofstream &savefile, bool islast)
{
string temp = "";//用来临时保存需要输出的文字
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= 9; j++)
{
if (j != 1) temp += " ";//每个数字之间需要一个空格
temp += result[i][j] + '0';//把每个数字转换成字符
}
temp += "
";//输出完一行需要换行
}
if (!islast) temp += "
";//如果这个不是最后一个棋盘,棋盘间需要再次换行。
savefile << temp;//把文字输入到文件中
}
5.测试运行
6.效能分析
n=1000时
7.PSP
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 40 | 45 |
· Estimate | · 估计这个任务需要多少时间 | 600 | 900 |
Development | 开发 | 480 | 780 |
· Analysis | · 需求分析 (包括学习新技术) | 60 | 90 |
· Design Spec | · 生成设计文档 | 20 | 35 |
· Design Review | · 设计复审 (和同事审核设计文档) | 20 | 0 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 5 |
· Design | · 具体设计 | 20 | 25 |
· Coding | · 具体编码 | 300 | 360 |
· Code Review | · 代码复审 | 30 | 15 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 100 |
Reporting | 报告 | 60 | 70 |
· Test Report | · 测试报告 | 60 | 50 |
· Size Measurement | · 计算工作量 | 10 | 0 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 15 |
合计 | 1780 | 2490 |
8.心得体会
这是第一次尝试使用Github工具,以及在markdown的排版上也花了一定时间。从拿到题目百度到后期自己思考、请教同学,也花了很多时间。希望以后的项目自己可以越做越顺利!