第二次作业——个人项目实战
项目需求
利用程序随机构造出N个已解答的数独棋盘 。
输入
数独棋盘题目个数N(0<N<=1000000)
输出
随机生成N个不重复的已解答完毕的数独棋盘,并输出到sudoku.txt中,输出格式见下输出示例。
[2017.9.4 新增要求] 在生成数独矩阵时,左上角的第一个数为:(学号后两位相加)% 9 + 1。例如学生A学号后2位是80,则该数字为(8+0)% 9 + 1 = 9。
Github地址
遇到的困难及解决方法
- 对于数独理解不够深刻,通过百度查找资料,了解到数独是99的棋盘中,每行每列以及每个33的九宫格中均不重复的填入1到9这九个数字;并且找到几个数独终盘观察棋盘特点。
- 自己用纸和笔倒是能一步一步达到数独终盘,但是让计算机来完成任务,我觉得这一直以来是我面临的最大问题!
-只能从最初步一点点思考,题目有要求说在第一个格子中填入特定的数字,顺其自然知道了第一行和第一列其他位置不再存在特定数字,直接在第一个格子中直接填入数字。- 比较容易想到的机器做法就是一个一个填入,在同学的提示下,意识到每填入一个数字,要对其进行行、列、宫的重复判断,如果重复了,需要退回上一个格子中重新填入,返回则需要用到递归函数,成功填入一个数字,则进入下一个递归函数,填入失败,退回上一个递归函数中。
关键代码&设计说明
void sudoku::getarea()
{
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
int a = (i - 1) / 3;
int b = (j - 1) / 3;
area[i][j] = a + b * 3 + 1;
}
}
}
- 在将99的整个棋盘分为9个33的小九宫格后,每个区域给一个标号分别为1到9,可通过上述函数计算出每个格子所在的区域。(ps:好吧,我承认我不太理解为什么能如此计算区域,感恩大佬相助。)
void sudoku::wrNum(int x, int y)
{
if (flag)return;
if (x < 9 || y < 9) {
int a = x;
int b = y + 1;
if (b > 9) {
b = 1;
a++;
}
int p = area[a][b];
int t = rand() % 9 + 1;
int r = t;
while (1) {
if (!row[a][r] && !column[b][r] && !place[p][r]) {
sudo[a][b] = r, row[a][r] = 1, column[b][r] = 1, place[p][r] = 1;
wrNum(a, b);
sudo[a][b] = 0, row[a][r] = 0, column[b][r] = 0, place[p][r] = 0;
}
r++;
if (r == 10)r = 1;
if (t == r)break;
}
}
else {
sum++;
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
cout << sudo[i][j];
if (j < 9)cout << " ";
}
cout << endl;
}
if (sum != n)cout << endl;
if (sum == n)flag = true;
}
}
- 上述函数即为填数的递归函数,row、column、place三个二维数组为判断当前行、列、宫是否存在当前要填的随机数。若行存在,则row当前位置为1,不存在为0,列和宫类比。若遇到数字重复的情况,填入的随机数自动加1,然后再次尝试填入,若循环一轮都不能填入,则退回上一层递归函数,另外只能填入1到9,当自加为10时,变为1,尝试填入。当行和列都填入超过9时,则开始输出,当输出个数与输入要求个数相同时,则退出本函数。
sudoku::sudoku()
{
memset(row, 0, sizeof(row));
memset(column, 0, sizeof(column));
memset(sudo, 0, sizeof(sudo));
memset(place, 0, sizeof(place));
sum = 0;
flag = false;
}
- 前文提到过要判断即将填入的随机数是否在当前行、列、宫中已存在,并通过三个二维数组记录情况,且最终形成的棋盘只存在1到9数字,所以将所有二维数组初始化为零,并不影响后续操作。
运行效果:
性能分析
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
· Estimate | · 估计这个任务需要多少时间 | ∞ | 1550 |
Development | 开发 | ||
· Analysis | · 需求分析 (包括学习新技术) | 120 | 150 |
· Design Spec | · 生成设计文档 | ||
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 0 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
· Design | · 具体设计 | 120 | 150 |
· Coding | · 具体编码 | 500 | 720 |
· Code Review | · 代码复审 | 60 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 150 |
Reporting | 报告 | 180 | 200 |
· Test Report | · 测试报告 | ||
· Size Measurement | · 计算工作量 | 30 | 60 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | ∞ | 1550 |
个人总结
- 不得不承认第一次完成大项目作业,感觉一个人完成难度颇大,多亏得到了周围同学不厌其烦的帮助,一点一点,挤牙膏般勉勉强强的完成了。主要体现出的问题是如何设计算法使得计算机能够完成要求的计算内容,遇到瓶颈时容易撞南墙不回头,要学习其他同学“绕路”解决问题的方式。另外,由于算法遇到了瓶颈,在翻阅大量博客的过程中,偶然间加到了一位博友,他现在已经参加工作,他自述现在主要在做前端方面,编程方面过去一直在做,我认为在写博客,阅览博客,认识到更多代码大神更是一份珍贵的财富。