主题:SUDOKU生成与破解算法 0.5
LostAbaddon
[专家分:40] 发布于 2006-07-02 13:16:00
VB6编写。其实对算法来说,语言的版本并不影响什么。用VB6的理由仅仅是这里有动态控件数组,用起来方便顺手而已。用VB.NET也不是不可以,算法部分的CODE几乎完全一样,只是读取和写入数据稍微兜点圈子而已。
生成部分除了没有设置难度调节以外,别的基本没问题,已经可以用了。难度调节部分要先建立模型看看各种密度分布下生成的SUDOKU的难度,这个有待破解部分完成以后来统计,不然几百几千的SUDOKU我人工来求要死人的。
破解部分还没有最后完成,因为破解的三条基本逻辑中只完成了前两个,最后一个算法实现太麻烦了,当然,也不是不可以。正在考虑是否有化简的办法。以现在已经完成的部分,有能力的读者可以提取出来写入CLASS中,然后用CLASS来做对不确定的可能项所有可能值的遍历,这样就可以解决所有SUDOKU了(原则上)。
全局数组SUDOKU中第三维从2到9这8个标号都没用,理由是本来这些地方是用来进行第三部逻辑运算的,现在对第三部逻辑还在思考,所以这8个标号暂时没用。事实上标号10等于没用……
[url=http://lostabaddon.spaces.msn.com/cns!EB06676D0B60BFBD!1889.entry]CODE[/url]
回复列表 (共10个回复)
沙发
euc [专家分:4310] 发布于 2006-07-02 21:55:00
给大家补充一下sudoku的介绍:
http://5233.blogchina.com/4177665.html
不过lz大师用什么算法实现的是什么功能都还没说呢...
板凳
rickone [专家分:15390] 发布于 2006-07-03 09:40:00
感觉蛮有意思呢,呵呵~~
初步想了一种搜索策略,因为如果直接搜对于有些难题(空格太多的)搜索量实在太大了,每一行是9!量级的,而且有9行,于是想到这样一个方法:对所有空格先取出来,做成这样一个结点
struct blanknode{
int count;//余下可用的数字个数
int used[10];//标记哪些数字已经使用过
};
一开始的时候,对所有空格扫描,扫描它所在的行和列以及小九宫格,让出现的数字标记出来,并算出余下的可用数字个数.最终就得到这样一个空格集S.
由S中的数据启发式地进行深搜,从S中取一个count最少但又不为零的结点出来,由used[]标记得到搜索子树,试探的同时改变同行同列以及同九宫格中其它的空格数据,递归,如果S中结点有矛盾,比如行列小九宫未完成而count又为0时,产生截断,直到所有空格count皆为0且所有空格填完时,得到一个可行解,输出.
暂时只想到这些.
3 楼
LostAbaddon [专家分:40] 发布于 2006-07-03 12:40:00
基本思路有三条,其中上面的算法实现了两条,因为第三条按照构思的算法感觉还不如直接就对可能结果遍历来得快,所以就放着没实现。
三条逻辑分别是:
1,以行或者列或者九宫为单位,看缺哪些数字,这些数字构成集合An(n=1,2,3,分别表示行的,列的和九宫的),对一个确定的位置,把它的A1,A2,A3求一个交,就是这个位置的所有可能值。当可能值唯一是,该点数值确定。
2,以一个九宫为单位,看一个点所在行的补行在九宫所在行内的值。把所有这些值中出现过两次的找出来,这些就是这个点的行可能值。同样去寻找这个点的列可能值,求并。当然,实际中不是这样,还要考虑边界因素,也就是某些补行可能在给定点的列上已经有值了,那么就认为这个补行覆盖了所有数。第二逻辑往往仅对第一逻辑中可能值不唯一的情况下对所有可能值遍历,这样可以缩小范围。
3,也就是所谓的第三逻辑,是最体现“推理”的一条。当所有空白点都没有确定值而只有不少于两个可能值的时候,根据可能值以九宫为单位的分布来推测别的列和行中的值分布。这个在WEBSUDOKU的HARD模式下经常要用的。
当上面三条逻辑都无效的时候,也就是只能得到一系列可能值而不能得到确定值的时候,再对所有可能值做遍历递归。这个是没办法的了,已经无法通过逻辑来判断值了,只能靠暴力破解了。
4 楼
LostAbaddon [专家分:40] 发布于 2006-07-03 12:49:00
然后说说生成SUDOKU的方法。
生成SUDOKU也遵循三条基本方针:
1,以九宫为单位,调换一行九宫内两个任意数字行,不破坏SUDOKU可行性。
2,以九宫为单位,调换一列九宫内两个任意数字列,不破坏SUDOKU可行性。
3,以数字为单位,做轮换群操作,不破坏SUDOKU可行性。
这三条规则中的第三条其实不增加SUDOKU复杂度,仅仅是让两个SUDOKU“看上去”不同而已。
第一和第二条还需要再次展开,因为如果不展开直接用的话,你会在玩了三个SUDOKU以后发现一个规律,是什么规律自己去玩了就知道了。
展开的规则是:把要调换的两行(列)构成一个轮换群,然后求该群的分解群(一般三个),然后一这个分解群为基本操作单位对行(列)A做正轮换,对行(列)B做逆轮换。
展开以后的第二第二条能生成更复杂的SUDOKU。
可以证明,对一个最简SUDOKU通过上面的三条规则,可以遍历所有SUDOKU。
显示的时候只要挖掉一些数字就好了。这里建议最后保留25到30个。数学家目前位置得到的最少保留数是18个,但是18个保留下来的SUDOKU的难度是EVIL级的,不推荐生成来给别人玩。何况这个模型的SUDOKU的挖数模式是固定的,因而解也是固定的。
至于生成挖掉数以后的SUDOKU的挖数方式,这里还没研究过。不是任意的挖法都能生成一个好的SUDOKU题的。好的SUDOKU题必须让答案是唯一的,而且尽量让玩家不用暴力破解。
5 楼
iAkiak [专家分:8460] 发布于 2006-07-03 22:22:00
厉害!我只做了破解,没想出生成。
期待挖数:)
6 楼
fuch [专家分:250] 发布于 2006-07-04 15:37:00
lz,直接DFS加一点剪枝运算量低得超出想象哈
我想问,生成如何控制难度?什么叫做难,什么叫做易?
7 楼
rickone [专家分:15390] 发布于 2006-07-05 00:06:00
楼上的,运算量低啥意思?
8 楼
LostAbaddon [专家分:40] 发布于 2006-07-05 12:48:00
你的运算量指的是什么?是CODE量还是运算时间?
SUDOKU的难和易的界定还没完全想透。
9 楼
LostAbaddon [专家分:40] 发布于 2006-07-11 23:38:00
考试完毕了,写了SUDOKU破解程序的完整版本。
至于挖数的还没怎么想过。
下面是代码:
[url=http://lostabaddon.spaces.msn.com/cns!EB06676D0B60BFBD!1986.entry]CODE[/url]
10 楼
linyuetian [专家分:310] 发布于 2006-07-13 11:37:00
高手云集,厉害厉害!
我来回复