类似华容道一类搜索中,状态的Hash方法(转)

标准的华容道游戏是在一个4*5的方阵中,布有一些各种形状的棋子,当然留有若干空格.你的任务是移动棋子,并把其中的一枚棋子移动到指定的位置,如以下布局,要求把上面的A棋子移动到最下方的中间(其中一个字母为一个棋子,*表示空格):
B A A C
B A A C
D E E F
G H I J
G * * J
 
解法就是朴素的,搜!
 
搜索有两个难点,一个是状态转移,一个是状态判重.对于本题来说,状态转移是简单的,只用考虑与空格相邻的棋子怎么运动就行了.不过注意,不能用移动空格来状态转移,因为很多时候要多个空格同时作用.
 
状态判重却要花点脑筋,自然是用Hash表,不过怎样去Hash?
 
直观的想法是,把布局图进行位压缩然后变成一个数字,不过是个很大的数字,可以吓死人.再想几秒钟就会发现刚才的想法是多么地愚蠢,因为把很多棋子拉散了的状态也考虑到了,而显然这些状态是不会出现的.
 
棋子的形状是固定的,因此可以开个数组保存每个棋子的形状.
 
然后,思考把每一个棋子左上角的坐标保存下来,不过,每一个棋子需要两个整数来记录,也不划算.其实这样也存在大量的多余状态,如A,B棋子同时在(1,1)就不可能存在.
 
我们来做一个实验,先把空格看作棋子,接着,你把一个布局中的棋子从上到下,从左到右地取出来,如上图为BACDEFGHIJkl,然后取一个空棋盘,按顺序把棋子添入其中,结果,得到一个一模一样的棋盘.
 
这启发我们用放置顺序来表示一个布局,不过仍然存在不足,因为有些棋子是一样的,如B,C,G,J.可以把他们看作一种棋子,比如都是B,然后让第一个取出的是B,第二个是C...
 
于是,如果设
##
##=A
 
#
#=B
 
##=C
 
#=D
 
空格=E
 
则上图状态的Hash码是BABDCDBDDBEE
 
而所有状态的Hash码也无非是A B B B B C D D D D E E这12个字母的不同组合而已.
 
这时,我们可以说,状态最多只有12!/(1!*4!*1!*4!*2!)种,其实还要少一些,因为以BBBA...打头的状态是不可能存在的,要解决这个我无能为力了,大家可以一起思考.
 
然后,用组合公式求得字符串的字典序号,或者看作一个5进制数,取模.前者的优点是无重复,后者的优点是速度快些.

posted @ 2011-04-12 19:34  Cranny  阅读(369)  评论(0编辑  收藏  举报