想要有效地散列15拼图状态的方法

时间:2013-12-23 23:41:13

标签: algorithm hash 8-puzzle

我正在通过Ant Colony Optimization实现一个15-puzzle解算器,我正在考虑一种有效地将每个状态散列为数字的方法,所以我浪费了最少的字节数。

状态由16个数字的列表表示,从0到15(0是空洞)。

喜欢:

  

[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0]

所以我想创建一个唯一的数字来识别该状态。 我可以将所有数字转换为基数为16的数字,但我认为这不是非常有效 有什么想法?。

由于

2 个答案:

答案 0 :(得分:6)

你的状态与16个元素的排列同构。一个45位的数字足以枚举那些(log2 16!),但如果它有益,我们也可以将其舍入到64位。问题在于在状态枚举中找到从状态到其位置的有效转换。

知道0..16中的每个数字只出现一次,我们可以创建16个log2的变量16 =每个4位,其中i th 变量表示数字i出现的位置。这有很多冗余:它需要log2(16)* 16位,但这恰好是64位。它可以非常有效地实现(未经测试的伪代码):

state2number(state):
  idx = 0
  for i in [0;16):
    val = state[i]
    idx |= i << (val * 4)
  return idx

我不知道这是否是“将所有数字转换为基数16”的意思。这是非常有效的,当展开和其他微优化时,它只有几十个周期。它需要两个以上的字节,但64位仍然相当节省空间,并且直接使用它作为某些数组的索引对于64和45位都不可行。

答案 1 :(得分:3)

有16个! = 2.09 * 10 ^ 13个可能需要约44.25位的状态。

因此,如果要以字节为单位对状态进行编码,则至少需要6个字节才能完成。

为什么不这样编码:
让我们命名值a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p

值可以是

b`:= b - (b>a)?1:0;
c`:= c - (c>a)?1:0 - (c>b)?1:0
d`:= d - (d>a)?1:0 - (d>b)?1:0 - (d>c)?1:0
....

hashNumber = a + b *15+c * 15 * 14 + d` * 15 * 14 * 15 + ....

这将为您提供每个可能的状态到6个字节的数字的双射映射。

如果你需要,将数字转换回其引用状态非常简单。


不是最佳但速度快:
每个数字使用4位(省略最后一个,因为它可以从之前的15个数字计算),需要15 * 4位= 60位。 可以存储在7.5个字节中,或者如果你可以浪费更多,只需使用8个字节。