---恢复内容开始---
一、Github地址: https://github.com/xiaxiaxiaxiajie/sudoku1962
二、PSP
PSP2.1 |
Personal Software Process Stages |
预估耗时 (分钟) |
实际耗时 (分钟) |
Planning |
计划 |
40 |
35 |
·Estimate |
·估计这个任务需要多少时间 |
20 |
20 |
Development |
开发 |
1100 |
1200 |
·Analysis |
·需求分析(包括学习新技术) |
180 |
210 |
·Design Spec |
·生成设计文档 |
120 |
150 |
·Design Review |
·设计复审 |
30 |
20 |
·Coding Standard |
·代码规范 |
30 |
30 |
·Design |
·具体设计 |
240 |
270 |
·Coding |
·具体编码 |
1200 |
1000 |
·Code Review |
·代码复审 |
120 |
300 |
·Test |
·测试 |
60 |
120 |
Reporting |
报告 |
120 |
120 |
·Test Report |
·测试报告 |
30 |
20 |
·Size Measurement |
·计算工作量 |
10 |
10 |
·Postmortem&Process Improvement Plan |
·事后总结并提出过程改进计划 |
80 |
80 |
|
合计 |
3260 |
3585 |
三、解题思路:
拿到题目看到要求时,有些词不知道是什么,感觉很麻烦,因此有不想做的心理(就是懒,真不好),开始着手分析题目后,首先要下手的就是代码部分,代码根据题目要求一共有两块,一块是解数独部分,一块是生成数独部分。
1. 解数独:
用dfs从第一排开始到最后一排,依次找到空格,从数字1到9循环,判断是否能填该数字(即当前数字所处横排、竖排、九宫格是否有该数字出现过),可以填,接着往下的dfs,不可以换数字,如果没有可填的数字,返回上一次。
2.生成数独终局
例如一个简单的数独以9为第一个数字(学号62:6+2+1=9)
9 1 2 3 4 5 6 7 8
3 4 5 6 7 8 9 1 2
6 7 8 9 1 2 3 4 5
1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
2 3 4 5 6 7 8 9 1
5 6 7 8 9 1 2 3 4
8 9 1 2 3 4 5 6 7
除了第一排第一个数之外,第一排的任意数的位置均可改变,个数为 8! = 40320 种,4、5 、6行可互换位置,7、8、9行可互换位置,即有 8! * 3!* 3! > 1e6 种。
四、代码设计
int main(int argc, char *argv[]) //主函数, 获取命令参数 bool judge(char *s)//判断输入的数是否有效 void creat_sudoku()//生成数独终局函数 void get_init()//在解数独中对应给定的数独对三个状态数组进行初始化 void dfs(int x, int y)//解数独函数,用dfs深度优先搜索 bool judge_shudu(int x, int y, int n)//判断x行y列这个位置是否可以放置数字n void output()//打印函数,将数独输出到指定的txt文件中
五、关键代码展示
1. 生成终局
void creat_sudoku()//生成数独终局函数 { m = 0;//记录当前生成多少个数独,n是要生成的数独数 int tmp[10] = { 0,9,1,2,3,4,5,6,7,8 };//tmp 1-9是第一行要生成的数 int moveleft[10] = { 0,0,3,6,1,4,7,2,5,8 }; //moveleft表示2-9行在第1行基础上整体左移位数 for (int i = 1; i <= 40320; i++) //8!=40320 { for (int j = 1; j <= 9; j++) shudu[1][j] = tmp[j]; for (int j = 2; j <= 9; j++) { for (int k = 1; k <= 9; k++) { int pos = k - moveleft[j]; if (pos <= 0) pos += 9; shudu[j][k] = shudu[1][pos]; } }//生成一个数独模板 int fol[10] = { 0,1,2,3,4,5,6,7,8,9 };//fol函数是接下来输出的1-9行对应数独模板的fol行 for (int j = 1; j <= 6; j++) { if (j != 1)next_permutation(fol + 4, fol + 7);//此函数是求4-7行的下一个排列 for (int k = 1; k <= 6; k++) { if (k != 1)next_permutation(fol + 7, fol + 10); for (int p = 1; p <= 9; p++) { for (int q = 1; q <= 9; q++) { if (q == 1)Output << shudu[fol[p]][q]; else Output << " " << shudu[fol[p]][q]; } Output << endl; } Output << endl; if (++m >= n) return; }//完成一次数独的输出 fol[7] = 7, fol[8] = 8, fol[9] = 9; }//每种数独模板可以输出36种子数独,所以最多能输出8!*36=1451520种 next_permutation(tmp + 2, tmp + 10);//对tmp函数进行一次全排列 } return; }
2. 解数独
void dfs(int x, int y)//解数独函数,用dfs深度优先搜索 { if (flag) return; if (y > 9) { x++; y = 1; } if (x == 10 && flag == 0) { output(); flag = 1; return; }//此时每一位都放置了数字,则输出 if (!shudu[x][y]) { for (int i = 1; i <= 9 && !flag; i++) { if (judge_shudu(x, y, i)) { line[x][i] = 1; orl[y][i] = 1; block[getblocknum(x, y)][i] = 1; shudu[x][y] = i; dfs(x, y + 1); line[x][i] = 0; orl[y][i] = 0; block[getblocknum(x, y)][i] = 0; shudu[x][y] = 0; } } } else dfs(x, y + 1); }//判断x行y列要放置1-9中的哪一位数字,递归实现
3. 单元测试
命令行参数测试: -c -s -1 -a
运行情况:-c 1 -c 1000 -c 100000 -s 文件路径
六、性能分析
1. 生成1000个数独终局
2. 生成1e6个数独
3. 解1个数独
4. 解10个数独
5. 解1000个数独
---恢复内容结束---