个人项目
个人项目博客
1.github项目地址
https://github.com/zhaobs-yu/sudoku
2.PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 5 | 5 |
· Estimate | · 估计这个任务需要多少时间 | 5 | 5 |
Development | 开发 | 670 | 910 |
· Analysis | · 需求分析 (包括学习新技术) | 120 | 240 |
· Design Spec | · 生成设计文档 | 5 | 5 |
· Design Review | · 设计复审 (和同事审核设计文档) | 2 | 2 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 3 | 3 |
· Design | · 具体设计 | 60 | 120 |
· Coding | · 具体编码 | 300 | 360 |
· Code Review | · 代码复审 | 60 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 120 |
Reporting | 报告 | 55 | 55 |
· Test Report | · 测试报告 | 30 | 30 |
· Size Measurement | · 计算工作量 | 5 | 5 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 20 |
合计 | 725 | 965 |
3.解题思路
拿到这个题目后,我想到的解题思路是首先解决解数独的部分,生成数独终局的时候就可以先随机生成数独残局,再利用解数独的方法把残局变为终局。
解数独这个部分我的思路是先把可以确定唯一答案的空格填好,找不到这样的空格的时候,就找一个只有两个候选数的空格进行尝试。不断重复这两个过程,最终就可以把数独解出来。
生成数独时我的方法是先往固定的几个格子里随机填写数字,形成一个数独残局,再用解数独的方法进行求解,生成数独终局。
4.设计实现过程
程序主要有以下这几个类。
- table包含一个数独表格的所有信息
- block是一个格子的数据
- row是一行的数据
- column是一列的数据
- area是一个九宫格的数据。
程序主要有一下几个函数:
- fill函数:给某一格填上某数,并刷新当前数独表格与之相关的所有数据。
- work1函数 :把一个数独残局中可以确定唯一答案的空格填好。
- solve函数:解一个数独残局。
- make1函数:生成一个数独残局。
- makemany函数:生成n个数独终局。
5.程序性能
由于我的算法简单粗暴,所以我找不到可以改进性能的地方。
下面是性能分析图
可见程序中消耗最大的函数是getcount,这个函数的作用是更新数独表格的候选数信息,每次填写一个数字以后都会调用getcount函数。
6.代码说明
1 int solve(table *table1) { 2 int point = 0; 3 //printtable(table1); 4 //printposs(table1); 5 getcount(table1); 6 //printcount(table1); 7 int exit = 0; 8 exit = work1(table1); 9 //printtable(table1); 10 //printposs(table1); 11 //printcount(table1); 12 check(table1); 13 tabletry[point] = *table1; 14 point++; 15 tabletry[point] = *fill(table1, tryi, tryn[0]); 16 point--; 17 tabletry[point] = *fill(&tabletry[point], tryi, tryn[1]); 18 point++; 19 if (exit == 0) { 20 while (1) { 21 //cout << "begin try" << tryi / 9 + 1 << "行" << tryi % 9 + 1 << "\n"; 22 error = work1(&tabletry[point]); 23 //printtable(&tabletry[point]); 24 //printposs(&tabletry[point]); 25 //printcount(&tabletry[point]); 26 if (error == -1) { 27 //cout << "try another"; 28 point--; 29 //cout << point << endl; 30 if (point < 0) { 31 //cout << "无解" << endl; 32 return -1; 33 } 34 } 35 else { 36 if (check(&tabletry[point]) == 1) { 37 //cout << "over" << endl; 38 //printtable(&tabletry[point]); 39 writetable(&tabletry[point]); 40 break; 41 } 42 else { 43 point++; 44 tabletry[point] = tabletry[point - 1]; 45 point++; 46 tabletry[point] = *fill(&tabletry[point - 2], tryi, tryn[0]); 47 point--; 48 tabletry[point] = *fill(&tabletry[point], tryi, tryn[1]); 49 point++; 50 } 51 } 52 } 53 } 54 else { 55 //cout << "无解" << endl; 56 return -1; 57 } 58 return 0; 59 }
solve函数先把数独表格中可以确定唯一答案的空格填好,找不到这样的空格的时候,就找一个只有两个候选数的空格进行尝试。不断重复这两个过程,直到解完数独或确定数独无解。
7.总结
生成数独终局的部分我没有使用任何现有的高效算法,而是自己写了一个随机填数再求解的算法,算法的性能非常差,也不能保证生成的数独不会重复。
我自己测试的时候是生成10000个数独要12.5秒,更多的我也没敢试,我觉得生成1000000个大约要20分钟吧。