来源:Facebook Hacker Cup Qualification Round 2011
在街机游戏中,您可以从您选择的位置玩一个简单的游戏,其中一个球落入游戏的顶部。当球落入游戏时,球会弹出许多钉子。每当球击中一个钉子时,它将以0.5的概率反弹到左边,并以0.5的概率向右反弹。唯一的例外是当它击中最左侧或右侧的钉子时,在这种情况下它总是向中间弹跳。
当游戏首次制作时,钉子以规则网格排列。然而,这是一个老游戏,现在一些钉子丢失了。你在游戏中的目标是让球在特定位置脱离游戏的底部。鉴于游戏的安排,我们如何确定丢球的最佳位置,以便将其送到这个特定位置的概率最大化?
下图显示了一个包含五行五列的游戏示例。请注意,顶行有五个钉,下一行有四个钉,接下来五个,依此类推。有五个列,有四种选择可以将球放入(从0开始索引)。请注意,在此示例中,缺少三个挂钩。第一行是第0行,最左边的第二行是第0列,因此缺失钉的坐标是(1,1),(2,1)和(3,2)。在这个例子中,丢球的最佳位置是在第0列的最左侧,这使得它有50%的几率在目标中结束。
x.x.x.x.x
x...x.x
x...x.x.x
x.x...x
x.x.x.x.x
G
x
表示挂钩,.
表示空格。
答案 0 :(得分:4)
从底部开始,为目标指定1的概率,为其他位置指定0的概率。然后对于下一行,按如下方式分配概率:
1) if there is no peg, use the probability directly below. 2) for a peg, use the average of the probabilities in the adjacent columns one row down.
这将简单地将概率传播到顶部,其中每个槽将被分配从该槽到达目标的概率。没有树,没有递归。
答案 1 :(得分:2)
我们可以使用概率论来解决这个问题。我们将球放在一个位置,并递归地将球的路径分成一个(在侧壁)或两个可能的方向。在第一步,我们以概率1知道球的位置(毕竟我们正在放弃它!)。在随后分成两个方向时,概率减半。如果我们最终位于目标位置的底行,我们将路径的概率添加到总计。对所有起始位置重复此过程,并达到达到目标的最高概率。
我们可以通过使用动态编程去除递归和逐行处理来改进此算法。从设置为全0的第一行开始,除了我们设置为1的起始位置。然后通过从0和0的数组开始计算到达下一行中每个单元的概率。对于当前行中的每个单元格,将其概率的一半加到下一行的左侧单元格中,将其一半加到右侧,除非它靠近侧壁,在这种情况下我们将完全概率添加到单个单元格。继续为每一行执行此操作,直到到达最后一行。
到目前为止,我们忽略了失踪的钉子。我们可以通过对每个单元格具有三个概率来考虑它们:一个球体当前行进的每个方向。最后,我们总结所有因为方向无关紧要。
答案 2 :(得分:0)
这个问题出现在2011年的Facebook黑客杯中。
marcog解决方案似乎是正确的,但我解决了一点不同。我这样解决了:对于每个可能的初始丢弃孔,按照以下步骤执行BFS:
我在cpp中的解决方案(不是最干净的代码)可以从以下网址下载:https://github.com/piva/Programming-Challenges/blob/master/peggame.cpp
希望有帮助...
答案 3 :(得分:0)
观察:
所以我会从底部开始,处于理想的位置,然后分散概率。缺失的钉子实际上只是跳过一排,所以你保留一个垂直落球的记录。
理想情况下,我会从一个完整的(斐波那契)树开始,并且对于每一行中缺失的钉子,会增加它们缺失的效果。
答案 4 :(得分:0)
O(R*C)
解决方案
dp[i][j]
给出球到达目标位置的概率,如果它当前位于第i行和第j行。
基本案例有dp[R-1][goal] = 1.0
,第R-1行的所有其他广告位都有0.0
然后重现
dp[i][j] = dp[i + 2][j] if the peg below is missing
dp[i][j] = dp[i + 1][left] if the peg is on the right wall
dp[i][j] = dp[i + 1][right] if the peg is on the left wall
dp[i][j] = (dp[i + 1][left] + dp[i + 1][right]) / 2 otherwise