对于数独游戏的研究,咱们难免要研究数独游戏的彻底解的生成算法,对于彻底解的生成过程,咱们通常是采用回溯法来产生整个九宫格的全部的数据。而对于九九八十一格的数独游戏完整解生成,咱们尝试按常规的回溯方法来实现,难免会出现回溯的解空间过于庞大而致使回溯的时间过长而没法知足游戏中咱们产生游戏彻底解的须要。为此,咱们须要一种高效的彻底解的生成算法,以知足咱们在数独游戏中快速的产生彻底解。对此,咱们须要对数独进行进一步的探索和研究。html
那首先咱们来了解一下数独游戏,数独的基本规则就是在以下图所示的大九宫格中的九九八十一格里随机填入1-9这九个数字中的任意一个,而且要保证每一横行、竖行的九个数字没有重复数字,还要保证每个小九宫格中的九个数字也不能重复。以下图,咱们将每个小九宫格涂上了不一样的颜色以便于区分。java
要生成合法的数独彻底解,那咱们必须了解数独彻底解的所具备的特性。那咱们下面看一组标准的数独彻底解的例子,以下所示咱们看到一组数独彻底解(这是咱们实现的算法生成的解)。算法
8 7 1 9 3 2 6 4 5 测试
4 9 5 8 6 1 2 3 7 url
6 3 2 7 5 4 8 1 9 spa
5 2 8 4 7 3 1 9 6 3d
9 1 3 6 2 5 7 8 4 htm
7 6 4 1 9 8 3 5 2 blog
2 8 7 3 4 9 5 6 1 排序
1 4 6 5 8 7 9 2 3
3 5 9 2 1 6 4 7 8
经过检查,咱们看到上面这一组解是知足数独规则的。但咱们为了研究数独彻底解的特性,须要将这一组解放入九宫格中进行分析,以下图咱们将这一组解放入到九宫格,首先咱们知道,整个大九宫格(九九八十一格)中咱们只能填入数字1-9,而咱们看到的是横行、竖行和小九宫格都是九格,也就是说,咱们在横行、竖行和小九宫格都必须使用到这九个数字。
若咱们要生成一组数独彻底解,那若是按传统的回溯方法来产生,那咱们首先会从第一个方格(从左至右,从上至下)开始,先从1-9九个数字中选取一个数字填入该处,而后咱们再从第二个方格开始,选取八个数字(按数独规则不能重复,则要除去刚刚填入的一个数字)中的一个,依此下去选填数字……固然后续方格中选择的数字,都会由于数独规则,使其所在横行、竖行和小九宫格中,其余已填方格中的数字对该处可填入的数字产生不一样的条件约束。某种状况下,咱们可能发现填到某格时,因为数独规则约束咱们已经没有数字能够填入该处了,这时候咱们就要开始回溯了,撤销上一步填入的数字,从新选择一个数字填入上一步的方格,而后继续开始本次的填数,若不行还得继续回溯。有时会由于某种制约,致使咱们要不停回溯撤销重填。若按照这种思路作下去,咱们发现因为解空间过于庞大,咱们能生成合适的彻底解可能要花比较长的时间。这样的算法思路根本没法知足咱们快速产生彻底解的须要。这时咱们想到要去缩小回溯的解空间,让回溯的解空间尽可能的减少。
因而咱们开始的新的算法探索,以下图经过分析咱们知道,1-9这九个数字必定都会被使用,并且是每一横行、竖行和每个小九宫格都会有1-9中的一个数字。首先咱们来对整个大九宫格进行划分,咱们将整个大九宫格划分为九个小九宫格。按从左至右,从上至下排序,也就是上面三个分别为1、2、3中间三个分别为4、5、6,而下面三个分别为7、8、9。那咱们先填1-9这九个数字中的“1”,咱们观察下面图例的解能够看到。在第一个小九宫格中填入一个“1”,在第2、三个小九宫格中也要填入一个“1”,而要知足数独规则,第二个小九宫格中填入的“1”就不能和第一个小九宫格的“1”在同一行,同时第三个小九宫格填入的数字“1”也不能和第1、二个小九宫格的“1”在同一行。以此类推下去,咱们继续填第4、5、6、7、8、九个小九宫格中的“1”,当第九个小九宫格数字“1”填完之后,整个过程彻底能够不用回溯。那咱们接着开始填入1-9这九个数字中数字“2”,在第一个小九宫格中咱们除去以前填入数字“1”被占用的位置,其余的八个空的方格咱们都是能够随便填的,咱们随机选取其中的一个空格,填入数字“2”。填完后,咱们接着填第二个小九宫格中的数字“2”,填入的位置要求仍是要知足数独规则的,在这里因为咱们在每一个小九宫格中1-9中的每一个数字都填过一次,因此这里彻底不用考虑小九宫格的数字不重复的问题,因此考虑的就是,每一横行、竖行是否知足数独规则,即填入的数字都不重复。这样咱们按照必定的顺序依次在九个小九宫格中填入1-9这九个数字。当九个小九宫格的数字“9”填完。整个大九宫格九九八十一个数字填入完毕,那么符合数独规则的彻底解也就应运而生。固然这里也会有回溯的状况产生,当咱们某个数字在填入某个小九宫格时,发现其可填空着的方格在横行、竖行上都已有该数字,那么这时咱们没法在此小九宫格填入该数字了,这时咱们要回溯到上一个小九宫格中,撤销这个小九宫格填入的该数字,从新选取可填位置填入该数字(这里不用选取数字,数字已选定)。填入完成后,再回到本次须要填入该数字的小九宫格中选填该数字。咱们须要把1-9这九个数字中的每个数字在九个小九宫格中按照数独规则都填入一遍。当第9个小九宫格中数字“9”填入完成,数独彻底解也就生成了。
该算法采用分治的思想将整个大九宫格分为九个小九宫格,1-9九个数字按顺序填入,排除了数字之间的限制约束,每一个数字独立填入的回溯空间大大缩小,某些数字甚至无需回溯,例如此过程当中的数字“1”和“9”就不须要进行回溯。同时咱们产生时结合随机数选填位置,这样能保在持数字之间很好的随机性的同时,又在产生时间上极大的缩短了耗时。这样思路实现的代码产生出来的数独彻底解,计算机耗时基本保持在几毫秒左右。就是以人工方式手动填入的方法,也可在几分钟以内产生一组合法的数独彻底解。此算法相较于传统的回溯算法,其效率明显的提升了不少。
为了便于区分咱们将1-9这九个数字标识不一样的颜色。填入完成后的解,以下图所示。最后经过咱们实现该算法的java代码的实际测试,其产生10000组解的实际平均耗时为3.25秒左右。实际测试中咱们使用的是笔记本,后台也有运行其余的软件,咱们有尝试将测试数据调至10000000组,该次测试过程当中CPU占用率平均在50%左右,笔记本有轻微发热,最后耗时为52.98分钟,固然这些测试中咱们并无去验证产生数独彻底解的惟一性,作这些测试只是为了验证数独彻底解的产生速度。
转自:http://blog.sina.com.cn/s/blog_a28e3dd90101e1i2.html