如何高效地为8球游戏排列台球?

34

由于八球游戏的球架可以根据多个规则进行设置,因此我指的是以下设置:

enter image description here

即8号球必须在中心,侧边必须交替放置条纹和固体球。其余两个球(一颗条纹和一颗固体)不重要。

假设你刚刚结束了一局比赛,收集了球,将它们放入球架中并准备开始新的比赛。它们现在是随机顺序。你该怎么办?

免责声明:下面为绘画作品

enter image description here

一种简单的方法是按照从上到下、从左到右的顺序开始。

例如,我们假设 1 在正确的位置。 5 不在正确的位置,我们将其与 2 交换,然后将 4 与 3 (或与 8 )交换,但这已经效率低下,因为我们已将 4 移至中心或将 8 放在 4 的位置-即不是最终所需的位置。

还有一个决定哪些类型的球应该放在角落的决定。你如何事先决定?是否应考虑已放置多少个球?在我的例子中,如果你想让灰色的在角落里,你已经有3个已放置的球(1,10,14)。如果你想要白色的在角落里,你只有2个放好了(2,11)。这是否重要?

为了形式化,我们可以假设有三种操作:

  • 交换相邻的两个球
  • 交换不相邻的两个球
  • 旋转球架

由于我们可以使用双手,让我们假设我们可以并行进行第一次操作(同时交换两对球),而我们一次只能交换两个不相邻的球。

什么方法最适合此任务以最小化时间(使用描述时间单位的时间)?贪心算法是否最佳? (当我整理它们时,我就是这样做的,我想)

编辑:根据现有(或先前的回答)-您可以假设在角落里比实心条纹更多意味着步幅将喜欢角落-不是说这不是正确的,但如果您做出这种假设,请证明它。


在设计算法时,我们应该假设在执行一次交换所需的时间内,我们可以进行多少次内存读取和比较?还是假定两者都可以任意快? - Patashu
@pst 我也考虑过这个问题,但是你怎么证明这是最有效的方法呢?直觉上,我实际上认为它并不是... - Luchian Grigore
@LuchianGrigore 有些问题可以得到最优解,而有些则不行。如果你打算在脑海中计算解决方案,那么你的非视觉记忆量会受到特别的限制。 - John Dvorak
@JanDvorak 在我脑海中的那部分只是额外加分,实际生活中我并不介意多走几步。所以,对于现实情况,我想启发式算法可能是我唯一能指望的了。但出于教育目的,看到一个最优算法也会很酷 :) - Luchian Grigore
1
@JanDvorak 实际上可以用2种方法完成 - (2-5/3-8)(12-11/4-3) - Luchian Grigore
显示剩余21条评论
5个回答

5

注意!此答案是在旋转要求之前编写的。请谨慎操作 :)

以下是我对问题的初步看法。

首先要做的是计算外部的奇偶性-如果它适合在角落里放置条纹,则为+1,如果适合在角落里放置实心,则为-1,如果是黑球则为+0。这使我们的范围从+12到-12,并且我们的目标是更接近的极端。(如果是+0,则选择+12或随机选择)

例如,这是+1 +1 +1 -1 -1 +1 -1 -1 -1 +1 +0 -1,因此它倾向于在角落里放置实心,即-1:

x o x x o
 x o x o
  8 x o
   o x
    o

下一步是把8号球移动到中心位置。如果你可以通过两次相邻的交换将两个球移动到合适的位置,而不是仅仅通过一次相邻交换将一个球移到正确位置(或者如果它在角落里则是一次非相邻交换),那么这样做。
x o x x o
 x 8 x o
  o x o
   o x
    o

在我们移动8号球之后,所有相邻球共享的两个交换的组合都可以通过一个非相邻的交换来产生,因此我们一次只需要考虑更少的复杂性。

按照以下优先顺序排序所有剩余的移动:

-外部两个相邻球之间的交换 “价值4” (如果是最后一个,则为2)

-外部球和内部相邻球之间的交换“价值2”(如果是最后一个,则为1)

-外部两个球之间的交换“价值2”

-两个球中一个在外部之间的交换“价值1”

并按照从上到下的顺序执行它们。

所以我们首先将上面的 o 向左移动(4),然后将右侧的 o 向内移动(2),接着将左下角的 o 向内移动(2),最后将顶部的 x 与中间的 o 交换(2)。我们完成了一个 2-2-1 的交换序列,即三步操作。

o x o x o
 x 8 x x
  o o o
   x x
    o

(值得注意的是,如果我们以角落的条纹为目标,这个问题也会同样快速地解决。)
x x o o x
 o 8 o x
  o x o
   x o
    x

我认为要求4次转弯是不可能的,但我还没有亲自证明。

另一个示例:

这个图案的奇偶性为+1,因此我们的目标是在角落处形成条纹:

8 o o o x
 o o o x
  o x x
   x x
    x

将8球与中心x交换位置

x o o o x
 o o o x
  o 8 x
   x x
    x

交换外部4个相邻的点(1-1)

x o o o x
 o o o x
  x 8 x
   o x
    x

将相邻边交换到中心,2个点 (1-2-)

x o o o x
 o o x o
  x 8 x
   o x
    x

将边缘与边缘交换,2个点 (1-2-1-)

x o x o x
 o o x o
  x 8 x
   o o
    x

三步走。

编辑:这对于开篇示例非常有效,只需两步即可解决:

这个有奇偶性为+1,所以我们的目标是角落中的条纹:

x x o o x
 o o x o
  o o 8
   x x
    x

在边缘将8和x互换,然后与中心的o互换(解决两个边缘) (2-)

x x o o x
 o o x o
  o 8 x
   x o
    x

交换顶部和底部左侧相邻的 o 和 x(解决四条边)(2-2-)

x o x o x
 o o x o
  x 8 x
   o o
    x

需要移动两次。


4次交换,2个时间测量 - (2-5/3-8)(12-11/4-3) - Luchian Grigore
我用3步解决了Blenders问题,还剩下一半:http://pastebin.com/MfRRGshn - Patashu
@Patashu:但这不还是四步吗?或者你把两个同时发生的交换算作一步了吗? - Blender
1
原帖说我可以每次进行两个相邻的交换或一个相邻的交换。这使得相邻的交换更有价值,因此我首先尽可能多地进行相邻的交换。 - Patashu
2
你能证明这个奇偶性方法是最优的吗? - Luchian Grigore
我很想这么做,但我不确定如何实现(除非编写一个程序来解决两种情况并逐个排除验证是否正确)。 - Patashu

4
你有两个八号球,作弊者。
在给定的例子中,解决方案需要2步:
2-5, 3-8 3-4, 11-12
最佳解决方案最好通过动态规划(DP)来配置问题。由于该问题是多阶段固定成本且没有不确定性,因此将存在一个DP矩阵,可以最优地解决该问题。
要创建矩阵:请注意,考虑到对称性,8球可能处于9个位置之一。固体可以以大约(14选择7)/ 2 = 1716种不同的方式排列。这意味着架构配置的总数约为1716 * 9 = 15,444。因此,您有15,444个不同的可能状态。计算从任何一个状态到任何其他状态的成本。这会得到一个具有15,444 * 15,444个单元格或约25亿个单元格的矩阵。识别所有最终状态单元格。要解决矩阵,您可以从起始状态向前广度搜索,直到达到终止状态(或直到达到当前最小成本的成本总额)。通过这样做,您将已经证明找到了所有最小成本路径。
请注意,上述解决方案有些天真,并且可以通过各种方式进行优化,以产生更小的矩阵。例如,您可以使用旋转对称性来减少单元格数量,并将成本1(用于旋转机架)添加到除在低中心位置之一具有8球的路径以外的正确路径中。
Pseudocode:

Create DP Matrix:

(1) determine number of possible arrangements, A, of balls
(2) for each arrangement, make a list of possible unique moves  
---- the possible moves are:  
------- rotating right  
------- rotating left  
------- exchanging any pair of balls  
------- exchanging any two pairs of adjacent balls  
(3) for each move in A store a pointer to the resulting arrangement  
(4) for each arrangment make an attribute indicating whether it is an end state  

Solve Problem  
(5) goto arrangement for starting position S  
(6) set best-cost-so-far (BCSF) variable to infinity
(6) breadth search from S, accumulating current cost CC as +1 for each transition
(7) if you reach an end state CC < BCSF, then set BCSF = CC and make solution list contain only the current path
(8) if you reach an end state CC = BCSF, then add path to solution list
(9) if CC > BCSF abandon branch and try next branch

The result will be a list of all possible solutions and the minimum cost BCSF.

这个“回溯”对我来说并不像DP。虽然我没有两个8号球,但我有14个球(标记为1-14)和一个8号球。 - Luchian Grigore
在DP中,您可以回溯或向前搜索。当您有许多可能的结束状态时,通常从起始状态向前搜索,而不是从结束状态回溯。您误解了组合计算的方式。要确定可能的排列,您从8球位置计数(A)开始,然后计算可能的实心排列(= 14选择7)(B)。在这样做之后,只有1个条纹排列,因此总组合是A * B * 1。如果使用对称性,则更加复杂,但近似总数如我所说。 - Tyler Durden
@LuchianGrigore:你真的有两个8球!一个黑色,一个白色(在中间)。7条纹+7整体+1黑色=15,但黑色的那个一个数字(八)。 - CSᵠ
我认为图像中的数字只是参考字符。黑色的八是“八号球”,其他的只是列举的“非八号球”。有点令人困惑,不可否认。 - moooeeeep

4

15!/(7!7!1!)=51480 种可能的位置。其中,有4个是最终状态:可以交换8号和9号球,同时可以颜色翻转。我们称这些位置的距离为0。

对于这4个位置中的每一个,生成所有可能的移动(1次或2次相邻的交换)。对于这些生成的尚未见过的位置,记住用于生成它的移动,并将这些位置的距离定义为1。然后对距离为1的每个位置执行同样的操作,并将新位置的距离定义为2。一直这样做,直到没有更多新的位置出现。

这利用了 @DPenner 指出的事实,即旋转总是可以被相邻的移动所替代。

由于交换是它们自己的逆运算,从位置A到B的移动也是把位置B带回A的移动。

因此,你得到了一个所有位置的列表,对于每个不是最终位置的位置,都有一个确定的移动可将其带回最终位置。

你会发现,至少需要4次移动才能到达232个位置。(编辑:我的邻接表之前有误。)例如:

      6-9,14-15     2-12       2-5,4-7       1-2
    x           x           x           x           o
   x x         x x         8 x         o x         x x
  x o x   =>  x o o   =>  x o o   =>  o 8 o   =>  o 8 o
 o o o x     o o x x     o o x x     x o x x     x o x x
o 8 o o x   o 8 o x o   o x o x o   o x o x o   o x o x o

没有任何初始位置需要超过4步才能解决。

编辑:首先将8号球交换的策略并不是最优的。例如:

         5-11     12-13,14-15    4-7,6-10
    x            x            x            x
   o o          o o          o o          o o
  o x o   =>   o 8 o   =>   o 8 o   =>   x 8 x
 x o x x      x o x x      x o x x      o o x o
8 x o x o    x x o x o    x o x o x    x o x o x

但我们可以做得更好:
         3-11       1-2,3-5
    x            x            o
   o o          o 8          x x
  o x o   =>   o x o   =>   o 8 o
 x o x x      x o x x      x o x x
8 x o x o    o x o x o    o x o x o

问题在于x是不适合角落的,因此我们会失去一步。相反,策略应该是寻找一个位置不对的球,但是它不能与相邻的球交换,因为它们要么是相同类型的,要么已经处于正确的位置。应该优先选择角落,因为它们有最少的相邻交换选项。它应该被正确类型的球替换。如果第一个球的最终位置上的球是错误类型的,则应选择一个错误位置的相邻球。这样,随后的相邻交换将把这些球放在正确的最终位置。
在上面的(反)例子中,8号球需要进行长时间交换才能到达最终位置。然而,在#5中的x是错误类型,所以我们与相邻的o进行交换,即第二行中的第二个o。
4步解决的早期示例如下:
        11-2         12-5        13-3       9-10
    x           x           x           x           x
   x x         o x         o x         o o         o o
  x o x   =>  x o x   =>  x 8 x   =>  x 8 x   =>  x 8 x
 o o o x     o o o x     o o o x     o o o x     o o x o
o 8 o o x   x 8 o o x   x o o o x   x o x o x   x o x o x

在第一步中,我们选择左下角的 o。第一个 x 位于第二个位置。然后我们选择 #12 上的 8,将其带回到 #5。接下来是底部行中间的 o。我们将其与下一个错误放置的 x 交换在 #3 上。最后,我们交换 #9 和 #10 以获得最终架子。路径与之前不同,但我们仍然用了 4 步完成了它。
编辑:还有一点:当进行相邻交换时,应优先考虑那些不会使两个球都到达它们的最终位置的交换。原因是这意味着至少需要两个移动,所以最好尽快进行第一次移动。
例如,问题中的架子可以在两个移动中解决:(2-4),(5,6) 和 (3-6),(12-13)。首先将 8 球移动到其最终位置,即使它与交换的白球还没有到达最终位置。如果首先进行两个边缘交换 (2-4),(12-13),仍然需要两个移动才能到达最终架子,总共需要三个移动,效果不佳。

你能否在此处提供一个链接,包含所有50k位置的最佳移动表以及其编码? - John Dvorak
“先换8球的策略并不是最优的。” 我认为你误解了 - 先打8球的策略不是为了让中心完整(三种颜色各一个),而是朝着更接近的填充边缘前进。在你所使用的例子中,棋盘极有可能在角落里完成实心球,因此我会采取有助于这一点的行动。将其与中心的实心球交换,然后在顶部角落进行两次相邻的交换以完成。 - Patashu
@Patashu,在我看来,这仍然会让你多出一步移动:旋转以将8球放在中心的顶部。我的启发式方法不会选择中心的实心球,因为它已经处于最终位置。 - Jeffrey Sax
“在中心顶部把8号球塞进去”从何时开始成为需求了?原帖只说8号球必须在中心,没有具体位置。如果我理解有误,那么你是正确的。 - Patashu
@Patashu 嗯,如果8号球可以在中心的任何地方,那么为什么还要将旋转作为选项呢?这本质上就是一个无操作。请参见DPenner有关旋转的问题以及OP在问题的评论中的答案(#17左右)。 - Jeffrey Sax
显示剩余2条评论

3

你好,首先我必须说这是一个非常有趣和有趣的问题,而且在堆叠时我没有想到过,尽管在15个球中一些额外的移动并不重要。

从堆叠描述和图像中,我们得到以下规则

  1. 角落总是相同类型的
  2. 每个侧面的中间总是与角落相同类型
  3. 接触角落的每组2个球总是相同类型(与角落相反的类型)
  4. 内三角形总是有8个球,条纹和实心(8个球在顶部)
  5. 在两侧,彼此靠近的球总是交替类型

如@DPenner在引理1中所述,旋转不是必需的,因为它们可以被交换替代,前提是成本相同。如果您是Rubick的粉丝,并选择使用它们,您只需要一个。

无法在少于4次交换中解决!(始终

您的示例图像最好证明这一点,无论如何计算,您都需要将6个颜色球从其位置上卸下,并将8ball =>那是3.5次交换,因为一个交换需要2个球,让我们将其四舍五入为4次交换。
这是为什么?
因为它不符合所有规则:

  • [5,1,4] [2,6] [11,13] [10,12] 不能彼此靠近(违反了5)
  • 8ball在侧面而不是在中间三角形中(违反了4)
  • [5,4] [6,12] [13,9] 不是所有相同类型(违反3),此外,在[1,5,4]的情况下,该集不与角落相反(再次违反3)
  • [2][11]与角落不是相同类型(违反2)

算法

8ball spots
第一步:修复8ball
将8ball交换到其位置。无论如何都需要它在那里。
这是旋转的唯一机会(如果8ball从内三角形开始,但位置不正确)

计数红色位置中最多的相同类型的球
最高计数球留下,其余的点必须被交换出去。

IF count is 3 {
    #inside triangle will choose 
    IF inside triangle has 2 of a kind, that type stays (in the red spots)
    ELSE pick random
}

开始交换:

  • 先交换角落的球(选择需要更换的一个球,找到对面的一个在角落的球)
  • 再交换中间的球(选择需要更换的一个球,找到对面的一个在边上中间的球)
  • 如果角落和中间的球已经交换完了,最后一个交换在内部三角形里

示例演示:

swap 8 with 3  #move1
count[stripe]=3 [6,13,9]  
count[solid]=3 [5,4,12]
highest count=3, checking inside, inside is correct, random pick: stripes stay
Pick 5, corners() correct, swap with middles(2)  #move2
Pick 4, corners() correct, swap with middles(11)  #move3
Pick 12, corners() correct, swap with middles(3)  #move4
Done.

如果随机选择,会选择实心保留:
Pick 6, swap with corners(10)  #move2
Pick 13, swap with corners(1)  #move3
Pick 9, swap with corners(14)  #move4
Done.

Demo2:

将3替换为7,用球号15代替“白球8号” demo2_with_ball_15

swap 8 with 3  #move1
count[stripe]=3 [6,13,9]  
count[solid]=3 [5,4,12]
highest count=3, checking inside, inside has 2 of a kind(stripes) => stripes stay
Pick 5, corners() correct, swap with middles(2)  #move2
Pick 4, corners() correct, swap with middles(11)  #move3
Pick 12, corners() correct, swap with middles(15)  #move4
Done.

玩得开心!

PS:你可能也会喜欢算法变体#2,它计数灰色位置,但我觉得在实际场景中使用红点更容易。


将第一个移动8球并不总是最优的选择 - 请看一下我回答中的第一个例子。首先移动8球会导致需要4步,而最优解只需要3步。 - DPenner1
@DPenner 注意,少的移动并不一定意味着更高效。可以同时完成的4个移动比不能同时完成的3个移动更有效率。 - Luchian Grigore
@LuchianGrigore 抱歉,有点词汇混淆 - 我将“移动”包括并行交换计算在内...然而,在那个球架中首先移动8号球似乎最多需要4次时间测量,而最优的是3次时间测量。不过如果我漏掉了什么,请告诉我。 - DPenner1
我根本没有考虑并行操作,只是想要一个通用算法,易于记忆且快速。我猜我的算法可以通过一种优先考虑角落(corners())/中心(middles())以寻找相邻球的方式来改进,但这种搜索会导致“处理能力”的浪费,这也应该与时间有关... - CSᵠ

3
这是一个具有挑战性、深受挫折感和乐趣的问题。我的猜测是以下是最优解决方案:
  • 根据Patashu的奇偶法则选择角落中的条纹或实心
  • 不旋转
  • 每次移动时,选择得分最高的移动,除非+3移动可以将8球放在中心位置
  • 如果平局,则选择无关紧要?编辑:请看底部注释。平局很难处理。

(我根据正确位置上的球数净差来评分移动。)

这里有两个示例架:

    x            8
   x x          o o
  o o x        o o x
 o o x x      o x x x
8 o o o x    o x x o x

如果我们从左到右,从上到下编号为1到15,则第一架架子的解法为(2-4/3-5)(5-11)(10-13),第二架架子的解法为(4-8/11-12)(5-10)(1-5)。我的最新证明尝试中有一部分在对称情况下失败了(上述两个例子是失败的变体)。以下是我在尝试中发现的两个引理,希望能帮助其他人进行证明。
引理1:旋转不是必要的
请注意,如果我们需要在某个时刻旋转解法,则无论何时(旋转不会改变任何可用交换),都没有关系。此外,我们只需要最多旋转一次,因为2次顺时针旋转=1次逆时针旋转,反之亦然。
因此,如果需要,让我们选择在最后一步进行旋转。此时,由于外部具有旋转对称性,外部必须是正确的。因此, 8号球将在三个中心球中的一个中。如果它在正确的位置上,我们就不需要旋转。否则,我们可以使用它,但请注意,交换也将完成架子。因此,在最优解中是不必要的。
引理2:如果Greedy策略在3次以内完成架子,则是最优的
令策略A为贪心解法,策略B为任何试图更快的非贪心解法。B必须进行至少一次非贪心移动。出于必要性,这不能是最后一步。因此,如果A需要n步才能完成一架架子,则 B 必须在第 n-2 步或之前进行其非贪心移动。这意味着如果A在2步或更少的时间内解决了架子,则它是最优的。
编辑:好吧,我刚刚在程序化测试中运行了我的算法,并发现它甚至不一致。实际上,似乎很难打破平局。请考虑以下架子:
    x
   o o
  x o x
 x 8 o x
x o o x o

我的算法会执行以下移动序列之一:(5-8/13-14)(7-8/10-15),(5-8/10-15)(7-8/13-14),(5-8/14-15)(10-13)(7-8),(5-8/14-15)(7-8)(10-13),(5-8/9-10)(14-15)(7-13),(5-8/9-10)(7-13)(14-15),(5-8/9-10)(13-14)(7-15)或(5-8/9-10)(7-15)(13-14)。前两个序列可以在最优的2个时间单位内解决它,但其他序列需要3个时间单位才能解决它。问题在于(14-15)和(9-10)的交换破坏了第二步可能出现的+4步骤。对该算法的修改可能需要前瞻,这很快就会变得复杂。我开始认为没有“简单”的解决方案,@JeffreySax提供的解决方案是可行的。还要注意,这个架子也打败了贪婪的解决方案。贪婪的解决方案将执行(13-14/10-15)(5-8)(7-8)或(13-14/10-15)(7-8)(5-8)。

猜想:永远不需要超过三步。如果你证明了这一点,我们就完成了。我有一个“超过四步”的证明,但它假设黑色在任何中心位置。 - John Dvorak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接