如何有效地为 8 球比赛打台球?

How to efficiently rack up billiards for an 8-ball game?

提问人:Luchian Grigore 提问时间:1/24/2013 最后编辑:Luchian Grigore 更新时间:2/7/2013 访问量:4335

问:

由于 8 球比赛的台球架可以在多种规则下进行,因此我指的是以下架子:

enter image description here

即 8 球必须在中心,并且沿侧面的条纹和固体必须交替出现。剩下的两个球(条纹球和实心球)无关紧要。

假设你刚刚完成了一场比赛,收集球,把它们放在架子上,然后继续安排它们开始新的游戏。它们现在按随机顺序排列。你如何进行?

免责声明:绘画艺术遵循

enter image description here

一个简单的方法是按顺序开始,从上到下>从左>右。

例如,我们假设它处于正确的位置。 不是,我们用 交换它,然后我们用 (或 用 ) 交换,但这已经是低效的了,因为我们要么将 移动到中心,要么移动到 的位置 - 即不是它必须在最后的位置。152438484

还有我们想要在角落里制作哪种类型的球的决定。你如何预先决定?您是否应该考虑已经放置了多少个球?在我的示例中,如果您想要角落中的灰色,那么您已经有 3 个(球 1,10,14)。如果你想在角落里有白色的,你只有 2 个 (2,11)。这应该重要吗?

为了正式化这一点,我们可以假设我们可以执行两个三个操作:

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

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

哪种方法最适合此任务,以最小化时间(以描述的时间单位)?贪婪是最好的吗?(我猜这就是我把它们架起来时的做法)

编辑:根据现有的(或以前的答案) - 你可能会认为角落里的条纹比实体多意味着大步会更喜欢角落 - 并不是说这不是真的,但如果你做出这个假设,请证明它。

算法 优化 与语言无关

评论

0赞 John Dvorak 1/24/2013
我对第一个操作的单手实现感兴趣,而且当双手并行执行时。
0赞 Luchian Grigore 1/24/2013
@JanDvorak很容易,只需稍加练习:)
0赞 John Dvorak 1/24/2013
使用不合适的排序不是更有效吗?
0赞 ckb 1/24/2013
让我想起了解决 15 个难题
1赞 Luchian Grigore 1/24/2013
@JanDvorak实际上可以在 2 中完成 - (2-5/3-8)(12-11/4-3)

答:

5赞 Patashu 1/24/2013 #1

注意!这个答案是在轮换要求之前写的。请自行谨慎行事:)

这是我对这个问题的初步看法。

首先要做的是计算外部的奇偶校验 - 如果它适合“角落中的条纹”,则为 +1,如果它适合“角落中的固体”,则为 +0,如果是 8 球。这给了我们一个从 +12 到 -12 的范围,我们的目标是更接近的极端值。(如果为 +0,则选择 +12 或随机)

例如,这是 +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 顶部与中间 (2) 的 o 交换。我们最终在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 交换 (1-)

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

3步。

编辑:这对于开篇文章中的示例非常有效,分两步解决:

它的奇偶校验为 +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

2步。

评论

0赞 Luchian Grigore 1/24/2013
4 次掉期,2 次措施 - (2-5/3-8)(12-11/4-3)
0赞 Patashu 1/24/2013
搅拌机 我在 3 步中解决了一个半步:pastebin.com/MfRRGshn
0赞 Blender 1/24/2013
@Patashu:那不也是四步吗?或者您是否将两个同时交换视为一次移动?
1赞 Patashu 1/24/2013
原来的帖子说我每次移动可以做两个相邻的交换或一个相邻的交换。这使得相邻的交换更有价值,所以我会先做尽可能多的交换。
2赞 Luchian Grigore 1/24/2013
你能证明这种奇偶校验方法是最佳的吗?
4赞 Tyler Durden 2/2/2013 #2

你有 2 个八球,作弊者。

在给定的示例中,解决方案需要 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 个细胞,或大约十亿个细胞的四分之一。识别所有最终状态单元。为了求解矩阵,您需要从起始状态向前搜索,直到达到结束状态(或直到您达到的总成本大于当前最小成本)。通过这样做,您将可以证明地找到了所有成本最低的路径。

请注意,上述解决方案有些幼稚,可以通过各种方式进行优化以产生更小的矩阵。例如,您可以使用旋转对称性来减少单元数,并将成本 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.

评论

0赞 Luchian Grigore 2/2/2013
这种“回溯”对我来说听起来并不像DP。我没有 2 个 8 球,我有 14 个球(标记为 1-14)加上一个 8 球。
0赞 Tyler Durden 2/2/2013
在 DP 中,您可以回溯或向前搜索。当您有许多可能的结束状态时,您通常从开始状态向前搜索,而不是从结束状态回溯。您误解了组合的计算方式。要确定可能的排列方式,请从 8 球位置计数 (A) 开始,然后计算可能的实心排列方式 (= 14 选择 7) (B)。这样做后,只有 1 个条纹排列,因此总组合为 A * B * 1。如果你使用对称性,它会更复杂,但近似的总数正如我所说。
0赞 CSᵠ 2/3/2013
@LuchianGrigore:你真的有两个8球!一黑一白(中间).7stripes+7whole+1black=15,但黑色的有一个数字(八)
0赞 moooeeeep 2/3/2013
我认为该图像中的数字只有参考字符。黑色的八球是八球,其他的只是列举的非八球诚然,这有点令人困惑。
3赞 DPenner1 2/2/2013 #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)。

我最近一次的证明尝试中,只有 11 个不同的机架在对称性上失败了一部分(上面显示的两个是失败的变体)。以下是我在尝试中发现的两个引理,希望它们能帮助其他人进行证明。

引理 1:不需要轮换

请注意,如果我们需要在解决方案中的某个点进行轮换,则何时进行轮换并不重要(轮换不会更改任何可用的交换)。此外,我们最多只需要旋转一圈,因为顺时针旋转 2 次 = 逆时针旋转 1 次,反之亦然。

因此,如果需要,让我们选择在最后一步进行轮换。此时,由于外部的旋转对称性,外部必须是正确的。因此,8 球将位于三个中心球之一中。如果它在正确的位置,我们不需要轮换。否则,我们可以使用它,但请注意,交换也会完成机架。因此,在最佳解决方案中没有必要。

引理 2:贪婪是最佳的,如果它在 3 步内解决机架

让策略成为贪婪的解决方案,让策略成为任何试图更快的非贪婪解决方案。 必须至少做出一个不贪婪的举动。这必然不能是最后一步。因此,如果用 n 个回合来完成一个机架,则必须在第 n-2 回合或更早的时候进行非贪婪移动。这意味着,如果在 2 圈或更短的时间内解决机架问题,则它是最佳的。ABBABA


编辑:好吧,我刚刚在编程测试中运行了我的算法,发现它甚至不一致。事实上,这种联系似乎很难打破。请考虑以下机架:

    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)。

评论

0赞 John Dvorak 2/4/2013
Conconencture:永远不需要超过三个动作。如果你证明了这一点,我们就完成了。我有一个“超过四个”的证明,但它在任何中心位置都假设是黑色的。
3赞 CSᵠ 2/3/2013 #4

Salut,首先我必须说这是一个非常有趣和有趣的问题,也是我在架子时没有想到的事情,尽管在总共 15 个球时,一些额外的动作并不重要。

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

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

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

少于 4 次交换无法解决!( 总是 )

您的示例图像最好证明这一点,无论您以哪种方式计算,您都需要将 6 个色球从它们的位置移开,而 8ball => 即 31/2 交换,因为交换需要 2 个球,让我们将其四舍五入为 4 个交换。
为什么会这样?
因为它不符合所有规则:

  • [5,1,4] [2,6] [11,13] [10,12]不能彼此靠近(中断 5)
  • 8ball在一边而不是中间三角形(断点 4)
  • [5,4] [6,12] [13,9]不是所有的类型都是一样的(断点 3),而且在集不对角的情况下(再次断点 3)[1,5,4]
  • [2]并且与拐角(断点 2)的类型不同[11]

算法

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

红色位置计算相同类型的球最多
数量最高的球会留下来,其余的位置必须换掉。

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.

演示2:

将 3 改为 7,将“白球 8 号”替换为 15 号球 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.

Have fun!

PS:您可能还喜欢灰色位置的算法变体#2,但是我发现在现实生活中使用红点更容易。counts

评论

0赞 DPenner1 2/4/2013
首先将 8 球移入并不总是最佳的 - 看看我答案中的第一个示例机架。首先移动 8 球导致需要 4 步,而最佳是 3 步。
0赞 Luchian Grigore 2/4/2013
@DPenner注意,更少的动作并不一定意味着更有效。可以并行的 4 个动作比不能并行的 3 个动作更有效率。
0赞 DPenner1 2/4/2013
@LuchianGrigore 对不起,有点词混淆 - 我算作包括平行掉期的“移动”......不过,在我看来,将 8 球移到那个架子上最多会导致 4 个时间测量,而最佳是 3 个时间测量。不过,如果我遗漏了什么,请告诉我。
0赞 CSᵠ 2/4/2013
我根本没有考虑并行运算,只是一个易于记忆且快速的通用算法。我想从这个意义上说,我的 alg 可以通过优先考虑 corners()/middles() 来寻找相邻的球来改进,但这种搜索意味着浪费“处理能力”,这也应该与时间有关......
4赞 Jeffrey Sax 2/3/2013 #5

有可能的位置。其中,4 个是最终的:球 8 和 9 可以交换,条纹/实心可以反转。我们会说这些位置的距离为 0。15!/(7!7!1!)=51480

对于这 4 个仓位中的每一个,生成所有可能的移动(1 个掉期或 2 个相邻掉期)。对于这些以前从未见过的移动生成的每个位置,请记住使用哪个移动来生成它,并给这些位置距离 1。然后对距离 1 处的每个位置执行相同的操作,并赋予新位置距离 2。继续这样做,直到没有更多的新职位。

这利用了这样一个事实,即正如@DPenner所指出的,旋转总是可以用相邻的移动来代替。

由于掉期是它们自己的反向,因此从位置 A 移动到 B 的移动也是将位置 B 带回 A 的移动。

因此,您最终会得到一个包含所有位置的列表,对于每个不是最终位置的位置,可以肯定的是,这将使其更接近最终位置。

您会发现有 232 个位置至少需要 4 次移动。(编辑:我的邻接表之前包含一个错误。例如:

      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(第 2 行中的第 2 个)进行交换。

前面的 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 位于位置 2。然后我们在 #12 处选择 8,我们可以将其带回家 #5。接下来是底行中间的 o。我们将其与#3处下一个错误放置的x交换。最后,我们交换 #9 和 #10 以获得最终机架。路径与以前不同,但我们仍然用 4 步走完了。

编辑:还有一点:在进行相邻交换时,应优先考虑那些最终没有将两个球都放在最终位置的球。原因是这意味着总共至少需要两步,因此最好尽快迈出第一步。

例如,问题中的齿条可以通过两步解决:(2-4),(5,6)和(3-6),(12-13)。8 球首先被移动到它的最终位置,即使它被交换的白球还没有在它的最终位置。如果先完成两次外围交换 (2-4)、(12-13),您仍然需要两步才能到达最终的机架,总共需要 3 步。

评论

0赞 DPenner1 2/4/2013
很好,我以为不需要 4 步——而且这个算法看起来很合理。
0赞 John Dvorak 2/4/2013
你能在这里转储一个链接,指向所有 50k 位置的最佳移动 + 其编码的表格吗?
0赞 Patashu 2/6/2013
“先换8球的策略不是最佳选择。”我想你误解了——8 球先的策略不是让中心完整(三种中的一种),而是走向更近的填充边缘。在你使用的示例中,电路板非常倾向于在角落里成为完整的实体,所以我会采取一个有助于这一点的举动。将其与中间的实体交换,然后在顶角进行两次相邻的交换以完成。
0赞 Jeffrey Sax 2/7/2013
@Patashu 在我看来,这仍然会给你留下一个额外的动作:旋转以将 8 球放在中心的顶部。我的启发式方法不会选择中间的实心球,因为它已经处于最终位置。
0赞 Patashu 2/7/2013
从什么时候开始,“把 8 球放在中心的顶部”成为一项要求?原来的帖子说 8 球必须在中心,而不是在哪里。如果我错了,那么你是对的。