一、 Github项目地址:
https://github.com/fangshuman/sudoku1940
二、各模块开发上的预估时间
(见篇末表格)
三、 解题思路
刚开始拿到题目的时候,首先看了pdf,因为不知道github是什么就无从下手。大概了解的是这个个人项目分为两个部分,但是经过整个项目的完成之后我觉得这个个人项目可分为四个部分:
1) 解数独部分
采用dfs逐个搜索空格,从1~9进行赋值,如果与已知数字不冲突则搜索下一格;如果与已知数字冲突则还原为空格0,并返回上层
2) 数独终局生成部分
先定义一行初始行,将初始行进行左移3位和左移6位的操作,可得到数独的前3行
再将第一行左移1位,得到中3行的第一行,再在此基础上进行左移3位和左移6位的操作,得到数独的中3行
同理,把第一行左移2位,得到后3行的第一行,再在此基础上进行左移3位和左移6位为操作,得到数独的后3行
举个例子:
5 1 2 3 4 6 7 8 9
3 4 6 7 8 9 5 1 2
7 8 9 5 1 2 3 4 6
1 2 3 4 6 7 8 9 5
4 6 7 8 9 5 1 2 3
8 9 5 1 2 3 4 6 7
2 3 4 6 7 8 9 5 1
6 7 8 9 5 1 2 3 4
9 5 1 2 3 4 6 7 8
这样的话第一行的数字就可确定整个数独终局。由于第一行第一个数字已经确定,则第一行剩余8个数字可产生的不同排列为8!=40320种
4,5,6行可进行任意的排列组合,就有6种不同终局,同理7,8,9行也可任意排列组合,又有6种不同终局
则通过行交换变换得到的有6×6=36种
与第一行8个数字不同排列的情况合并,一共有40320×36=1451520种,一定满足1e6的题目条件
3) 将两部分合并成为完整代码
4) 上传至github
有关如何上传到github,百度了好久,也找了好几种方法,特别是标题写了最简便上传github的博客,我最终都失败了,最后找的那个虽然内容很多步骤也很多但至少最后成功了
参考链接:https://www.cnblogs.com/specter45/p/github.html
四、设计实现过程
1) 函数功能
int main(int argc, char* argv[]) //主函数,获取命令参数,这里主要负责输入和判别功能
void output(); //输出数独
/*解数独部分函数*/
//负责从左上角开始搜索空格,并填入数字,运行过程中利用check判断所填的数字合不合法 void dfs(int x, int y);
//用于判断(x,y)上填写数字a是否符合数独规则,符合返回1,不符合返回0 int check(int x, int y, int a);
/*数独终局生成部分*/
//负责生成数独板,n为所需的数独终局的局数,运行过程中利用createLine进行行的生成,利用swapLine进行行的交换
void createBoard(long n);
//生成行,通过移位来生成行,属于同一矩阵的移动3位,属于上下相邻矩阵的移动1位,createLine(k)可生成k,k+1,k+2三行
void createLine(int k);
//交换行,通过该函数可将初始图进行更多变换,swapLine(line1,line2)将line1行与line2行交换
void swapLine(int line1, int line2);
2) 解数独部分dfs流程图
3)单元测试设计
测试命令行的判定:-s -c -a ab
运行情况判定:-c 6 -c 1000000 -c 0 -s input文件路径
五、性能分析
1) 生成6个数独终局
2) 生成1000000(1e6)个数独终局
3) 解12个数独
4) 解1000个数独
六、代码说明
1) 解数独
//判断填入的数字是否会有冲突 int check(int x, int y, int a) { int i, j; for (i = 0; i < 9; i++) { if (num[x][i] == a && i != y) //搜索横排 return false; else if (num[i][y] == a && i != x) //搜索竖排 return false; } int start_x = x / 3 * 3; int start_y = y / 3 * 3; int end_x = x / 3 * 3 + 2; int end_y = y / 3 * 3 + 2; for (i = start_x; i <= end_x; i++) //搜索九宫格 for (j = start_y; j <= end_y; j++) if (num[i][j] == a && i != x && j != y) return false; return true; } //dfs搜索填写数字 void dfs(int x, int y) { int i; if (y == 9) { x++; y = 0; } if (x == 9 && y == 0) //边界 { output(); flag = true; //如果输出过就不要再继续输出其他解 } if (!num[x][y]) { for (i = 1; i <= 9; i++) { num[x][y] = i; if (check(x, y, i)) dfs(x, y + 1); if (flag) return; num[x][y] = 0; //还原为空格 } } else dfs(x, y + 1); }
2) 生成数独终局
//产生行 void createLine(int k) { int i; for (i = 0; i < 9; i++) num[k][i] = line[i]; //设置第一行 for (i = 0; i < 6; i++) //设置第二行 num[k + 1][i] = line[i + 3]; for (i = 0; i < 3; i++) num[k + 1][i + 6] = line[i]; for (i = 0; i < 3; i++) num[k + 2][i] = line[i + 6]; //设置第三行 for (i = 0; i < 6; i++) num[k + 2][i + 3] = line[i]; } //产生数独终局 void createBoard(long n) { int i, j, a; memset(num, 0, sizeof(0)); for (a = 0; a < 40320; a++) //8!=40320,第一行8个数字共8!种排列组合的方式 { for (i = 0; i < 9; i++) //跳转createLine准备设置前三行 line[i] = orl[i]; createLine(0); for (i = 0; i < 8; i++) //跳转createLine准备设置中三行 line[i] = orl[i + 1]; line[8] = orl[0]; createLine(3); for (i = 0; i < 7; i++) //跳转createLine准备设置后三行 line[i] = orl[i + 2]; line[7] = orl[0]; line[8] = orl[1]; createLine(6); //完成初始图,4-6行,7-9行可进行交换形成更多新终局 for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { swapLine(i * 3 + 3 + 0, i * 3 + 3 + 1); output(); if (--n == 0) break; swapLine(i * 3 + 3 + 1, i * 3 + 3 + 2); output(); if (--n == 0) break; } if (n == 0) break; } if (n == 0) break; next_permutation(orl + 1, orl + 9); //重置第一行,共有8!种重置方法 } } //交换行 void swapLine(int line1, int line2) { int tmp[9]; int i; for (i = 0; i < 9; i++) tmp[i] = num[line1][i]; for (i = 0; i < 9; i++) num[line1][i] = num[line2][i]; for (i = 0; i < 9; i++) num[line2][i] = tmp[i]; return; }
七、各模块开发上的实际时间
(见篇末表格)
PSP2.1表格
PSP2.1 |
Personal Software Process Stages |
预估耗时 (分钟) |
实际耗时 (分钟) |
Planning |
计划 |
60 |
45 |
·Estimate |
·估计这个任务需要多少时间 |
15 |
20 |
Development |
开发 |
1500 |
1200 |
·Analysis |
·需求分析(包括学习新技术) |
100 |
220 |
·Design Spec |
·生成设计文档 |
120 |
300 |
·Design Review |
·设计复审 |
20 |
20 |
·Coding Standard |
·代码规范 |
25 |
25 |
·Design |
·具体设计 |
250 |
280 |
·Coding |
·具体编码 |
1200 |
1320 |
·Code Review |
·代码复审 |
60 |
45 |
·Test |
·测试 |
30 |
60 |
Reporting |
报告 |
80 |
100 |
·Test Report |
·测试报告 |
30 |
15 |
·Size Measurement |
·计算工作量 |
15 |
15 |
·Postmortem&Process Improvement Plan |
·事后总结并提出过程改进计划 |
60 |
80 |
|
合计 |
3565 |
3745 |