数独问题高效算法研究与实现
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数独问题高效算法的研究与实现
摘要:数独益智游戏(sudoku)是近年来全球流行的一种智力游戏。
本文通过分析数据结构、“非循环判断”预处理算法和回溯算法,深入探讨了数独问题的解决方案,并给出了该方案的实现算法,实验证明该算法是正确高效的。
关键词:数独;非循环判断;算法;回溯法
中图分类号:tp302
“数独”益智游戏(sudoku)是瑞士数学家欧拉发明的,目前在国内外非常流行。
游戏在9*9的单元表格中进行,单元表格不仅被分为9行、9列,也被分为3*3个九宫格。
单元表格中已存在若干数字,其余为空格。
游戏规则要求玩家在每个空格中填入1~9之间的数字,使每个数字在每行、每列、每个九宫格仅出现一次。
国内许多论文对数独游戏的教学意义做了深入讨论,但研究其求解算法的论文不多[1],用计算机进行快速求解的算法更少,参考文献[2]使用“有限递推”预处理提高了算法的执行速度,但其本身每次都要处理候选数字也耗时不少;参考文献[3]提出了效率较高的算法,但其冲突检测还可提高效率。
本文对“数独”游戏进行深入研究后用c语言设计出一种基于“非循环判断”预处理的回溯算法,然后用参考文献[2]中的三个实例及号称世界上迄今难度最大的数独游戏[4](芬兰数学家因卡拉花费3个月时间设计的)进行测试,实践证明该算法正确且高效。
1 数据结构与回溯法简介
1.1 数据结构
精心设计的数据结构可让算法更加高效[5]。
主要的数据结构是5个整型数组,其中2个一维数组,3个二维数组:
(1)int aresult [81],该数组的用途是接收题目(空白处则初始值为0)以及保存最终结果(所有的9*9个数字按序存储在该数组中);
(2)int aempty [81],该数组记载空白单元表格的序号和试填数字(前2位表示序号,第3位表示数字),这样既可减少搜索空间又方便下一次试填数字(原试填数字+1);
(3)int arow [9][9],该数组标识某行某个数字是否存在,减少判断时间;
(4)int acol[9][9],该数组标识某列某个数字是否存在,减少判断时间;
(5)int anine [9][9],该数组标识某九宫格某个数字是否存在,减少判断时间。
1.2 回溯法简介
回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。
探索到某一步,发现原先选择并不优或达不到目标时,就退回一步重新选择[6]。
2 预处理算法
在读取数独问题时用特定数组记载空白单元表格的序号,过滤掉已填数字表格,减少搜索空间;判断某一空格能否填入某一数字时
本文采用“非循环判断”预处理算法(一般采用循环判断[2][3]),该算法思想是:按序扫描问题时,对原有数字进行预处理,即根据该格序号及数字对arow、acol和anine数组进行相应标记,如:第9格(下标从0开始)的数字为5,预处理时该格行号为1、列号为0、九宫格序号为0,结果为:arow[1][4]=1,acol [0][4]=1,anine [0][4]=1,则表明第1行、第0列和第0九宫格不能填数字5。
3 算法设计
(1)读入数独问题。
(2)给数组aempty、aresult、arow、acol 和anine赋初值。
(3)按序扫描问题,把未填数字的空格序号乘以10后存入aempty 数组,把已填数字或0按序号存入aresult数组,同时根据序号及已经填的数字给arow、acol和anine数组进行预处理。
(4)如果aempty数组中存在未填写数字的空格序号,则从aempty 数组中取出一个未填写数字的空格序号,否则执行(11)。
(5)把取出的空格序号进行行号、列号及九宫格序号分解。
(6)从数字1开始直到数字9尝试填写,并对其行、列及九宫格进行冲突判断,若尝试成功执行(7),否则执行(8)。
(7)执行相应标识处理后转到(4)。
(8)退回到上一个填数序号,若该填数序号存在则执行相应标识处理后执行(9),否则执行(12)。
(9)如果原来填写数字的下一个数字存在,对原来填写数字的
下一个数字尝试填写。
(10)下一个数字尝试填写成功执行(7),否则执行(8)。
(11)成功找到1个解,退出。
(12)无解,退出。
//关键源代码
void getanswer(int tx)
{
// tx表示未填空格数
while (no // bnum表示小格试填数字
for (num = bnum+1; num < 10; num++)
{
if (arow[row][num - 1] == 1) continue; //判断同行
if (acol[col][num - 1] == 1) continue; //判断同列
if (anine[jno][num - 1] == 1) continue; //判断九宫格aresult[tno] = num; //填数字
arow[row][num - 1] = 1; //标识行
acol[col][num - 1] = 1; //标识列
anine[jno][num - 1] = 1; //标识九宫格
aempty[no] = tno * 10 + num; //第no个为”序号*10+数字”no++;
rflag = 1;
break; //填好1个就跳出for循环
}
//没有填数
if (no==0)
{
printf(”no answer\n”);
break;
}
else if(rflag==0)
{
no--; //返回上一数重填
}
}
}
4 实例测试
前3个实例取自参考文献[2],第4个实例出自芬兰数学家因卡拉[4]:
下面是对上述4题各计算5次的时间测试结果(在操作系统xp 和cpu为amd 4600+(2.4g)的环境下测试的):从上面结果可知,一般的数独难题(包括号称世界上迄今难度最大的数独游戏)可在15ms内找出答案;由此可见,本算法是高效的;通过检验本算法所给答案也是正确的。
参考文献:
[1]王琼,邹晟.数独问题的求解、评价与生成算法的研究[j].南京师范大学学报(工程技术版),2010,10(1):76-79.
[2]雷蕾,沈富可.关于数独问题的算法的设计与实现[j].电脑知识与技术,2007,2(2):481-482.
[3]李盘荣.“数独”游戏的算法研究与实现[j].电脑知识与技术,2008,3(8):1715-1717.
[4]http:
///news/sh/2013-05-26/144777326.html.
[5]严蔚敏,吴伟民.数据结构[m].北京:清华大学出版社.
[6]http:///view/45.htm.
作者简介:姜华林(1971-),男,土家族,贵州省遵义市人,讲师,硕士(西南大学),主要研究方向为:软件设计与开发,算法设计与分析。
作者单位:遵义职业技术学院,贵州遵义 563000。