[4,1,3,2] [] []
也就是说,有3个堆栈的空间,其中1个堆满了数字.此外,假设您的堆栈计算机可以执行2次移动:移动b(将a的顶部元素放在b上),并加入b(将堆栈放在堆栈b的顶部).在这种情况下,最佳排序是:
move 0 1 move 0 1 move 0 2 join 1 2 move 0 2
这将执行以下序列:
[4,1,3,2] → [4,1,3] → [4,1] → [4] → [4] → [] [] → [2] → [2,3] → [2,3] → [] → [] [] → [] → [] → [1] → [1,2,3] → [1,2,3,4]
在给定初始堆栈配置的情况下,您如何找到这样的最佳运动集来对第一个堆栈上的列表进行排序?
由于这个简单的问题可能没有任何简单的解决方案,我不会试图找到一个完整的解决方案,而是试图向您提供一些可能导致您正确方向的点(或说服您放弃).我看到了解决这个问题的两种不同方法:
分析方法
理论家的方法是尝试找到一个能够计算游戏任何给定位置复杂度的函数.最理想的是,这将是完成游戏所需的步骤数.如果找到这样的复杂度函数,那么在每个位置都很容易检查可能的下一个移动,计算它们之后的位置的复杂性,然后选择产生最不复杂位置的移动.
应该通过将完成的游戏的复杂性设置为0来开始搜索这样的函数.然后,应该为可能的操作定义对称的向后操作.移动操作本身是对称的,因此可以按原样使用.但是必须用unjoin替换join-operation,它会在中间的任何位置切换任何堆栈,并将其结尾移动到空堆栈中.在此之后,任何一个移动或未连接操作都可以达到的位置将具有复杂度1.然后,从那些位置可以达到并且没有更低复杂度的任何位置将具有2的复杂度.然后,应该尝试搜索可以生成可以计算任意位置复杂度的函数的模式.
这种方法可能提供一种非常优雅和有效的解决方案,可能很容易被证明是最佳的.但明显的缺点是无法保证存在这种复杂功能 – 至少在任何实际形式中都是如此.
一台状态机
我最初认为更有希望的一种不同方法可以是定义一组关于玩家应该在某些特征的位置采用什么计划的规则.在这种情况下,将根据其特征对位置进行分类,并且对于给定类别中的位置,将定义特定计划.然后,位置类基本上是状态机中的状态,并且计划在状态之间转换.
状态和计划的示例将是起始位置,其中数字1(最低值)位于堆栈中间的某处.在这种情况下,一个可行的计划可能是将1上的所有数字移动到其中一个空堆栈,当显示1时,将其移动到另一个空堆栈作为最终排序堆栈的起始点.
这些州及其相关计划的清单将是一个相当夸张,但也许是可行的.然而,更大的问题是证明州内的计划是最优的.例如,我给出的起始位置的计划肯定是合乎逻辑的,但不能保证它是最优的.
对这种方法持怀疑态度的想法是以下想法:特别是在具有较长起始堆栈的游戏中,最好的排序策略可能是将长堆栈划分为具有特定划分的另外两个堆栈,然后将两个或三个堆栈再次连接到一个长堆栈,再次划分并重复直到堆栈已排序.在这种情况下,很难预测如何对两个堆栈进行划分,因为明显的计划可能不起作用.例如,将数字除以更小和更大数字的堆栈是没有意义的,因为这种部分排序将在下一轮被破坏.一个更好的计划可能是创建尽可能多的连续数字对,但不是说这也是最优的.
总之,我认为如果搜索出最佳结果,这个问题很可能只有蛮力解决方案.肯定有至少从一般分类科学中找到好结果的方法,但绝对最优是超出它们的.