简而言之:如何散列一个免费的多骨牌?
这可以概括为:如何有效地散列任意二维整数坐标集合,其中一个集合包含唯一的非负整数对,当且仅当没有平移、旋转或翻转可以映射它时,一个集合才被认为是唯一的与另一组相同?
对于不耐烦的读者,请注意我完全了解蛮力方法。我正在寻找一种更好的方法——或者一个非常有说服力的证据,证明没有其他方法存在。
我正在研究一些不同的算法来生成随机polyominos。我想测试它们的输出以确定它们的随机性——即给定订单的某些实例比其他实例更频繁地生成。从视觉上看,很容易识别自由多骨牌的不同方向,例如以下维基百科插图显示了“F”五联骨牌的所有 8 个方向(来源):
如何在这个 polyomino 上加上一个数字 - 也就是说,散列一个免费的 polyomino?我不想依赖于“命名”多米诺骨牌的预填充列表。无论如何,广泛同意的名称只存在于订单 4 和 5。
这不一定等同于枚举给定顺序的所有自由(或单边,或固定)多骨牌。我只想计算给定配置出现的次数。如果一个生成算法从不产生某个 polyomino,那么它就不会被计算在内。
计数的基本逻辑是:
testcount = 10000 // Arbitrary
order = 6 // Create hexominos in this test
hashcounts = new hashtable
for i = 1 to testcount
poly = GenerateRandomPolyomino(order)
hash = PolyHash(poly)
if hashcounts.contains(hash) then
hashcounts[hash]++
else
hashcounts[hash] = 1
我正在寻找的是一种有效的PolyHash
算法。输入的多米诺骨牌被简单地定义为一组坐标。例如,T tetronimo 的一个方向可以是:
[[1,0], [0,1], [1,1], [2,1]]:
|012
-+---
0| X
1|XXX
您可以假设输入的 polyomino 已经标准化为与 X 和 Y 轴对齐并且只有正坐标。正式地,每组:
- 将至少有 1 个坐标,其中 x 值为 0
- 将至少有 1 个坐标,其中 y 值为 0
- 不会有 x < 0 或 y < 0 的任何坐标
我真的在寻找新的算法来避免一般蛮力方法所需的整数运算数量的增加,如下所述。
蛮力
此处和此处建议的蛮力解决方案包括使用每个坐标作为二进制标志将每个集合散列为无符号整数,并采用所有可能旋转(在我的情况下为翻转)的最小散列,其中每个旋转/翻转也必须是翻译为原点。这导致每个输入集总共进行 23 次集合操作以获得“免费”哈希:
- 旋转 (6x)
- 翻转 (1x)
- 翻译 (7x)
- 哈希 (8x)
- 找到最小的计算哈希 (1x)
获得每个哈希的操作顺序是:
- 哈希
- 旋转、平移、散列
- 旋转、平移、散列
- 旋转、平移、散列
- 翻转、翻译、散列
- 旋转、平移、散列
- 旋转、平移、散列
- 旋转、平移、散列