0.项目
项目地址:https://github.com/John-zjm/suduku
GUI地址:https://github.com/John-zjm/sudoku_Gui
1.需求分析
需求分析
1.生成终局 格式:sudoku.exe -c n
1)不重复
2)1<=n<=1000000,能处理非法参数
4)n在1000以内时,要求程序在 60 s 内给出结果
5)输出生成的数独终盘至sudoku.txt
2. 求解数独 格式:sudoku.exe -s path
1)从指定文件读取,每读81个数字视作一道数独题,忽略其他字符
2)要求文件内的数独题目是合法的
3)文件内数独个数在1000以内时,要求程序在 60 s 内给出结果
4)输出已读入数独的答案至sudoku.txt。若存在未满81个的数字,在已解出的答案后输出“存在错误格式!”
2.解题思路
- 我主要把项目分为三部分:
- 输入部分
- 生成数独终局
- 解数独
在写界面的时,只要稍作修改就可以使用后两部分。
详细描述一下这三个部分:
输入略过,有Python的异常处理很好写
生成数独终局用的是行列变换法。数独中间的九宫格经过行列变换可以变换为2!×3!×3!×2!×3!×3!=5184(因为固定左上角为5)。这样我需要生成1000000/5184=192个九宫格就够了,而正中九宫格有8!=40320个足够满足要求。
解数独我主要参考了《数独求解的候选数优化算法设计》这篇论文,运用了显性候选数规则、隐性候选数规则、九宫格交叉排除规则。Python的numpy可以很好的对数组进行计算。在进行dfs时,我对候选数进行了估值,具体是(10-候选个数) + 同行确定数字个数 + 同列确实数字个数
3.设计实现
- 输入处理类:
根据参数调用下列函数进行相应处理(包括参数合法性判断) - 终盘生成类:
种子生成函数、交换组合函数、行列交换函数、转换输出函数 - 数独求解类:
初始化函数、记录函数函数、检错函数、恢复函数、深度优先遍历函数、评价函数、减少候选数函数。
单元测试:
“错误参数”:
sudoku.exe -c 20
sudoku.exe -c 1000000
sudoku.exe -s C:\Users\0\OneDrive\1.txt
sudoku.exe -s C:\
sudoku.exe -p asd
“错误数独”
sudo=[[1,2,3,4,5,6,7,8,9]for row in range(9)]
sudo=[[0 for col in range(9)]for row in range(9)]
sudo =[[8,0,0, 0,0,0, 0,0,0]
[0,0,3, 6,0,0, 0,0,0]
[0,7,0, 0,9,0, 2,0,0]
[0,5,0, 0,0,7, 0,0,0]
[0,0,0, 0,4,5, 7,0,0]
[0,0,0, 1,0,0, 0,3,0]
[0,0,1, 0,0,0, 0,6,8]
[0,0,8, 5,0,0, 0,1,0]
[0,9,0, 0,0,0, 4,0,0]]
4.性能改进
- 把输出改为一次输出,输入改为一次读入,多次处理。
- 在回溯时,用估值函数,让价值大的候选数先进循环
- 在界面中,把检测数独从全部检测,改为对修改数的所在行,所在列,所在九宫格进行检测。
由图可以看出combine()和check_one_possible()消耗较大
def combine(self, c1, c2, c3, r1, r2, r3):
self.table = deepcopy(self.temp)
if (c1 == 1):
self.colExchange(1, 2)