我正在研究一个涉及 3D(立方)无限细胞自动机的挑战,其定义为:
初始状态:我们从位于立方体顶点的 8 个单元开始,每个单元处于 4 种状态之一 {0:粉色、1:红色、2:绿色、3:蓝色}。
增长:在每一步中,立方体都会通过在每对现有单元之间插入新单元来扩展。新单元的状态由其最近邻居的状态总和模 4 确定。请注意,根据其位置,新单元有 2、4 或 8 个最近邻居(这是 3D Moore 邻域)。
为了说明这一点,下面是第一步的说明:
初始状态
步骤 1
例如,中心节点为绿色,因为它有 8 个邻居,它们的类型总和为 2(绿色)+ 1(红色)+ 1(红色)+ 0(粉色)+ 2(绿色)+ 0(粉色)+ 3(蓝色)+ 1(红色)= 10 % 4 = 2(绿色)
第 2 步
我们感兴趣的是追踪每个状态 [0, 1, 2, 3] 的细胞数量的演变。以下是第一步的计数:
- 初始:2、3、2、1
- 步骤 1:6、10、7、4
- 第 2 步:30、36、31、28
- 步骤 3:196、192、155、186
- 步骤 4:1'162、1'276、1'207、1'268
我们的目标是确定第 19 步中每个细胞状态的数量。鉴于指数增长,蛮力是不可行的。有人告诉我可以在不到一秒的时间内解决它。有人知道如何解决这个问题吗?
提前感谢您的帮助!
我们可以为每个可能的“小”立方体(即 8 个角相邻的立方体)创建一个计数器。因此,对于角顺序为红色、红色、绿色、粉色、粉色、绿色、蓝色、蓝色的立方体,我们将有一个计数器,同样,对于八种颜色的每个不同序列,我们也会有不同的计数器(注意:顺序很重要)。
每次我们“扩展”到下一步(生成),这样的 2x2x2 立方体就会变成 3x3x3 立方体:我们掌握了了解 3x3x3 立方体的 27 种颜色的所有信息。然后我们减去 2x2x2 立方体的计数(因为它不再存在),然后增加 3x3x3 立方体中包含的八个子 2x2x2 立方体的计数器。同样,我们知道相关颜色,因此我们知道要增加哪些计数器。
在第 19 代(或者如果我们愿意,在每一代),我们可以根据每个可能的 2x2x2 立方体中“第一个”角(即最接近原点的角)的颜色来聚合这些计数器。这样,我们将计算最后一代中的所有“节点”,除了位于完整结构外侧的 3 个平面之一上的节点,包括距离原点最远的(最后一个)节点(示例输入中的顶部红色节点)。对于这些平面,我们可以维护其上的 2D 面的计数器,并在最后计算这些面的“第一个”角的计数器。同样,这将考虑几乎所有节点,除了位于三个外部 1D线上的节点,这些线上的节点包括距离原点最远的(最后一个)节点。我们还可以维护这些边(即节点对)的计数器,并根据每对的第一个颜色聚合它们。这样就只剩下一个未被考虑的节点,也就是距离原点最远的最后一个节点。
该计数器数组具有以下数量的条目:
这是合理的内存块,在大多数编程语言中可以在几毫秒内进行迭代和更新。
当我用 JavaScript 编写此代码时,我发现最终结果超出了 2 53,因此我不得不使用 BigInt 数据类型作为计数器。但是,这些数字适合 64 位整数,因此如果您的编程语言具有该数据类型,则不需要动态 Big Integer 数据类型。
以下是 JavaScript 的实现,您可以在此处运行:
即使生成了输出,在我的笔记本电脑上,这个程序也能在一秒钟内完成。用低级语言(如 C)编写的程序应该会更快。