【问题标题】:Probability of death of a man moving n steps in a matrix在矩阵中移动 n 步的人的死亡概率
【发布时间】:2013-05-07 12:01:57
【问题描述】:

有一个岛,用方阵nxn表示。

岛上的一个人站在任何给定的坐标 (x,y) 上。他可以在岛上向右、向左、向上、向下一步向任何方向移动。如果他走出岛,他就会死。

让岛屿表示为 (0,0) 到 (n-1,n-1)(即 nxn 矩阵),并且人站在给定的坐标 (x,y) 处。他被允许在岛上移动 n 步(沿着矩阵)。他在岛上走了 n 步后死亡的概率是多少?

使用编程技术找到概率的方法应该是什么?

我有一个数学方法,但我不知道它是否正确。这里是:

结果总数为 n^n。计算可能导致该人死亡的结果数量:

对于四个方向中的每一个,检查多少步可以导致他走出矩阵。然后,应用高中概率公式。例如假设他可以走的总步数是5; (x, y) = (2,1) [索引从 0 开始]。因此,他需要在北目录中采取 3 步。掉出岛。将它们保持在一个组中:(NNN)并将其他 2 个步骤作为 4 个选择中的任何一个,我们有公式:4*4*3。同样,对于其他 3 个方向。最后,概率=(计算出的死亡结果之和)/(总结果)

这是一个谷歌面试问题。

【问题讨论】:

  • 当然,获胜的策略是站着不动,死亡的概率为 0。正如你所说,这个问题完全没有激励这个人采取任何步骤,它是完全模糊了他为什么要踏入任何危险。
  • @HighPerformanceMark 我不认为这是关于“获胜”,基本上是关于第三方计算如果他采取 n 随机步骤(据我所知)死亡的概率。跨度>
  • @Dukeling:我想你一定是误解了这个问题。如果 OP 想问一个关于在格子上随机行走(s)的问题,他会这样做的!?不,我认为这更像是一个关于找到最长寿命策略的问题。
  • @HighPerformanceMark "What is the probability that he is dead after he walks n steps on the island?" 这并不是说你必须选择步骤(公平地说,它也没有说随机行走)。此外,OP 对这个问题的尝试似乎表明只是计算概率。 "random walk on a lattice" 是相当高级的术语,我们都知道问题通常不会完全按照意思表达。但是,对所做的假设进行更多争论不会具有建设性,OP 必须澄清。
  • Sankalp,请编辑问题并说出 n 和 N 是否相关。还说如果每一步的方向是随机的,并且四个方向的可能性相等。

标签: algorithm recursion matrix dynamic-programming


【解决方案1】:

感谢 Anubhav C 提供上述出色的解决方案,这对阐明问题的解决方案非常有帮助。 我认为使用 0.25 作为概率(上面提到的)可能会产生误导和错误!如果我们查看#dead_cases/#total_possible_moves 的概率,结果会有所不同。

考虑以下代码来查找死亡/幸存案例:

def winLoss_stat(N, steps):
    newStats = [[[0, 0, 0] for i in range(N)] for j in range(N)]
    if steps==0:
        newStats = [[[1, 0, 0] for i in range(N)] for j in range(N)]
        return newStats
    oldStats = winLoss_stat(N, steps-1)
    for i in range(N):
        for j in range(N):
            for d in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
                indX = i + d[0]
                indY = j + d[1]
                if indX >=0 and indX < N and indY >= 0 and indY<N:
                    newStats[i][j][0] += oldStats[indX][indY][0]
                    newStats[i][j][1] += oldStats[indX][indY][1]
                    newStats[i][j][2] += oldStats[indX][indY][2]
                else:
                    newStats[i][j][1] += 1
                    if steps==1:
                        newStats[i][j][2] = 1
    return newStats

(or equivalently, for one step (using dfs - recursive):

class winLoss:
    def __init__(self, N):
        self.win = 0 
        self.loss = 0
        self.N = N
    def winLoss(self, x, y, n):
        if x < 0 or y < 0 or x >= self.N or y >= self.N:
            self.loss += 1
            return
        if n == 0:
            self.win += 1
            return
        self.winLoss(x - 1, y, n-1)
        self.winLoss(x, y - 1, n-1)
        self.winLoss(x+1, y, n-1)
        self.winLoss(x, y+1, n-1)



    wl = winLoss(n)
    wl.winLoss(i, j, n)
for any i,j start point and n (size of square)
)

The winLoss_stat returns three values for starting point at each square i, j: 
[numbers of survive cases, numbers of die cases before or at k steps, numbers of death exactly at step k]

The results are as the following for n=4 (4X4), steps=4:

              0              1              2             3
0  [58, 24, 12]   [93, 34, 18]   [93, 34, 18]  [58, 24, 12]
1  [93, 34, 18]  [150, 46, 28]  [150, 46, 28]  [93, 34, 18]
2  [93, 34, 18]  [150, 46, 28]  [150, 46, 28]  [93, 34, 18]
3  [58, 24, 12]   [93, 34, 18]   [93, 34, 18]  [58, 24, 12]

This translates to the following probabilities for 
1. death before or at k steps:
          0         1         2         3
0  0.292683  0.267717  0.267717  0.292683
1  0.267717  0.234694  0.234694  0.267717
2  0.267717  0.234694  0.234694  0.267717
3  0.292683  0.267717  0.267717  0.292683

2. death exactly at k steps:
          0         1         2         3
0  0.146341  0.141732  0.141732  0.146341
1  0.141732  0.142857  0.142857  0.141732
2  0.141732  0.142857  0.142857  0.141732
3  0.146341  0.141732  0.141732  0.146341

The results can be verified by looking at the numbers of win-loss from step 1 to 3 for n=3:

winLoss_stat(3, 1)
           0          1          2
0  [2, 2, 1]  [3, 1, 1]  [2, 2, 1]
1  [3, 1, 1]  [4, 0, 0]  [3, 1, 1]
2  [2, 2, 1]  [3, 1, 1]  [2, 2, 1]

winLoss_stat(3, 2)
           0           1          2
0  [6, 4, 2]   [8, 5, 2]  [6, 4, 2]
1  [8, 5, 2]  [12, 4, 4]  [8, 5, 2]
2  [6, 4, 2]   [8, 5, 2]  [6, 4, 2]

winLoss_stat(3, 3)
             0            1            2
0  [16, 12, 4]  [24, 13, 8]  [16, 12, 4]
1  [24, 13, 8]  [32, 20, 8]  [24, 13, 8]
2  [16, 12, 4]  [24, 13, 8]  [16, 12, 4]

【讨论】:

    【解决方案2】:

    方法应该依靠概率公式 - 有利案例数/案例总数

    给定坐标 (x,y) 和步数 - n 用户可以采取步骤的方式总数 -
    第一步 - 4 种方法 第二步 - 4 * 3(假设他不能后退) 第三步 - 4* 3^2 ... …… ... 第 n 步 - 4*3^(n-1) 算术进展将给出总步数。

    Farovable 案例 - 即跨越边界 - 递归函数在所有 4 个方向上递归,并且每当越过矩阵边界时增加变量计数。

    将两者分开以获得答案。

    【讨论】:

      【解决方案3】:

      TL;DR:递归。 (或者“数学归纳法”,如果你很势利的话。)

      (在下文中,“he is dead after he walks n steps on the island”被假定为“他在小于或等于n 步后死亡”。如果你理解为“他正好在n 步骤之后死掉”,答案会略有不同。我会在最后简要讨论。)

      我们有一个NxN 矩阵,其中每个单元格中的值表示如果我们从该单元格开始,在n 步骤中死亡的概率。

      考虑在0 步中死亡的概率。显然,岛内的每个位置都是0.0,岛外的任何地方都是1.0

      1 步骤中死亡的概率是多少?你有四个方向可以移动,概率相同。因此,对于每个细胞,你取它的四个邻居,找出它们在0 步骤中死亡的概率,然后将它们平均在一起。 (如果邻居在矩阵之外,你认为它的概率是1.0。)

      类似地,从给定单元格开始以k 步死亡的概率是从其相邻单元格开始以k-1 步死亡的概率的平均值。

      Python 代码:

      from itertools import product as prod 
      
      def prob_death(island_size, steps):
          if island_size < 1 or steps < 0: raise ValueError
          new_prob = [[0. for i in range(island_size)] for j in range(island_size)]
          if steps == 0:
              return new_prob
          old_prob = prob_death(island_size, steps - 1)
          directions = [(0, -1), (1, 0), (0, 1), (-1, 0)]
          for (i, j, direction) in prod(range(island_size), range(island_size), directions):
              neighbor_i = i + direction[0]
              neighbor_j = j + direction[1]
              if neighbor_i >= 0 and neighbor_i < island_size and \
                      neighbor_j >= 0 and neighbor_j < island_size:
                  prob_death_this_way = old_prob[neighbor_i][neighbor_j]
              else: # neighbor is outside the island 
                  prob_death_this_way = 1.
              new_prob[i][j] += 0.25* prob_death_this_way
          return new_prob
      

      现在,让我们测试一下:(mpr 只是一个很好地打印矩阵的函数)

      >>> mpr(prob_death(5, 0))
      0.000000 0.000000 0.000000 0.000000 0.000000
      0.000000 0.000000 0.000000 0.000000 0.000000
      0.000000 0.000000 0.000000 0.000000 0.000000
      0.000000 0.000000 0.000000 0.000000 0.000000
      0.000000 0.000000 0.000000 0.000000 0.000000
      

      正如所料:如果你从岛内开始,你不会在 0 步内死亡。

      >>> mpr(prob_death(5,1))
      0.500000 0.250000 0.250000 0.250000 0.500000
      0.250000 0.000000 0.000000 0.000000 0.250000
      0.250000 0.000000 0.000000 0.000000 0.250000
      0.250000 0.000000 0.000000 0.000000 0.250000
      0.500000 0.250000 0.250000 0.250000 0.500000
      

      这是我们所期望的。如果您从角落牢房开始,您有0.5 一步内死亡的概率:您的 4 个邻居中有 2 个在岛外。如果你从边缘开始,只有 1 个邻居在外面,所以你的死亡概率是0.25。在其他任何地方,所有邻居都在岛内,因此一步死亡的概率是0.0

      >>> mpr(prob_death(5, 5))
      0.806641 0.666016 0.622070 0.666016 0.806641
      0.666016 0.437500 0.349609 0.437500 0.666016
      0.622070 0.349609 0.261719 0.349609 0.622070
      0.666016 0.437500 0.349609 0.437500 0.666016
      0.806641 0.666016 0.622070 0.666016 0.806641
      

      在 5 个步骤中死亡的概率。我无法验证确切的值,但它看起来是正确的:角落的死亡概率最高,边缘略低,并且向内稳步下降。

      这解决了在小于或等于n 步数内死亡的问题。

      现在,要找到在 准确 n 步内死亡的概率:让从 (x,y) 开始的小于或等于 n 步内的死亡概率记为 @987654346 @。那么恰好在n 步中死亡的概率是在n-1 步中存活的概率乘以在nth 步中死亡的概率,假设我们存活了n-1 步:(1-P(x,y,n-1))*(P(x,y,n) - P(x,y,n-1))。 (我不太确定这个公式;如果我错了,请纠正我。)

      【讨论】:

      • 有一个 parity 参数暗示了一些简化。考虑以棋盘格图案标记为黑色或白色的位置;每一步都会改变颜色。因此,如果您想以 n 步从 (a,b) 移动到 (c,d),并且 (a-c) + (b-d) 是奇数,那么如果 n 是偶数,则概率为零。做不到。反之亦然。因此,对于 n 的一半值(奇数或偶数 n),您可以立即说概率为零。
      • 我没看到。问题是“跳出董事会的概率是多少?”可视化“外部”的明显方法是将棋盘向各个方向扩展一个正方形。但是现在“外面”有两种颜色的正方形,所以我看不出我不能以任何数量的步骤去任何颜色的事实有什么用。
      • 有人能解释一下为什么我们将每种方式的概率除以 4(或乘以 0.25)吗?我明白了,否则总和将超过 1。但我不明白数学逻辑。
      • @sachin2182 他可以向四个方向移动(上、下、左、右)。所以向任何特定方向迈进的概率是 0.25。
      • @AnubhavC 干净且解释清楚..!! \m/
      【解决方案4】:

      首先,从第 0 步中出现在正方形 (x, y) 中的概率的矩阵开始。让我们用一个 4x4 矩阵来模拟它。假设这个人从 (1, 2) 开始:

      After 0 steps:
        0.00%   0.00%   0.00%   0.00%
        0.00%   0.00% 100.00%   0.00%
        0.00%   0.00%   0.00%   0.00%
        0.00%   0.00%   0.00%   0.00%
      outside:   0.00%
      ----
      After 1 steps:
        0.00%   0.00%  25.00%   0.00%
        0.00%  25.00%   0.00%  25.00%
        0.00%   0.00%  25.00%   0.00%
        0.00%   0.00%   0.00%   0.00%
      outside:   0.00%
      ----
      After 2 steps:
        0.00%  12.50%   0.00%  12.50%
        6.25%   0.00%  25.00%   0.00%
        0.00%  12.50%   0.00%  12.50%
        0.00%   0.00%   6.25%   0.00%
      outside:  12.50%
      ----
      After 3 steps:
        4.69%   0.00%  12.50%   0.00%
        0.00%  14.06%   0.00%  12.50%
        4.69%   0.00%  14.06%   0.00%
        0.00%   4.69%   0.00%   4.69%
      outside:  28.12%
      ----
      After 4 steps:
        0.00%   7.81%   0.00%   6.25%
        5.86%   0.00%  13.28%   0.00%
        0.00%   9.38%   0.00%   7.81%
        2.34%   0.00%   5.86%   0.00%
      outside:  41.41%
      ----
      

      这是一个计算这个的python程序:

      class Table:
          def __init__(self, n, outside=0):
              self.T = [[0]*n for i in xrange(n)]
              self.outside = outside
      
          def add(self, i, j, value):
              n = len(self.T)
              if 0<=i<n and 0<=j<n:
                  self.T[i][j] += value
              else:
                  self.outside += value
      
          def make_next(self):
              n = len(self.T)
              Q = Table(n, self.outside)
      
              for i in xrange(n):
                  for j in xrange(n):
                      value = self.T[i][j] / 4.0
                      Q.add(i-1, j, value)
                      Q.add(i+1, j, value)
                      Q.add(i, j-1, value)
                      Q.add(i, j+1, value)
              return Q
      
          def __repr__(self):
              return '\n'.join(' '.join(
                          '{:6.2f}%'.format(item*100) 
                          for item in line)
                          for line in self.T) + \
                     '\noutside: {}'.format('{:6.2f}%'.format(self.outside*100))
      
      
      N = 4
      T = Table(N)
      T.add(1, 2, 1)
      
      for k in xrange(N+1):
          print 'After {} steps:'.format(k)
          print T
          print '----'
      
          T = T.make_next()
      

      【讨论】:

      • 我认为您的概率略有缺陷。如果前 4 步中的 2 步导致他死亡,那将是 50%,那么这 2 步未死棋的所有未来步法将占另外 50%。例如,不应说这 2 步中的某一步与第 50 步具有相同的概率。
      • 您可能只能在每一步将outside 乘以 4(我认为在make_next 的开头)。这应该会产生正确的概率。
      • @Dukeling 将value = self.T[i][j] 更改为value = self.T[i][j] / 4.0,您将看到实际概率。您会看到 T+outside 中所有值的总和正好等于 1。其他版本显示在每个步骤中结束的案例数。
      • @Dukeling 我现在明白你的意思了。你完全正确。现在修复它。
      • 您答错了问题。这家伙不是从 (0,0) 开始的;他可以在任何点 (x,y)。 “从所有可能位置开始的概率”在这里无关紧要;我们想要在 n 步内死亡的概率,因为他从 (x,y) 开始。
      【解决方案5】:

      这是一个非常复杂和微妙的问题——我怀疑面试官的目标不是听到你想出答案,而是看看你如何解决问题。

      问题变成了一个棋盘 n 个方格在一边,棋子显然是随机放置的,必须移动 n 个空格,每个棋子都在一个明显随机的基本方向上移动转动。因此,棋子离开棋盘的概率不仅与棋盘的大小有关,还与棋子的位置有关。由于任何离开棋盘的动作也算作离开棋盘,因此棋子所采用的路径也是相关的。

      对于 2×2 网格,棋子有 2/7 的概率留在棋盘上(四个路径留在棋盘上,总共 14 个路径,与四个可能的起点中的哪一个无关)。

      对于 3×3 的网格,如果棋子从角落开始,则棋子有 2/11 的概率留在棋盘上(16 条路径留在棋盘上,总共 88 条路径)。如果它从一侧开始,它有 3/11 的概率(24 条路径保持打开)。如果它从中心开始,它有 9/22 的概率(36 条路径保持打开)。由于棋子有 4/9 的概率从角或边开始,1/9 的概率从中心开始,它留在棋盘上的总概率为 (2/11 + 3/11) × 4/9 + 9/22 × 1/9 = 0.247。

      4×4 网格变得(显然)更加复杂,但可能值得注意的是,网格确实符合一种模式:

      2×2

      - - 1 - -
      - 2 - 2 -
      1 - 2 - 1
      - 2 - 2 -
      - - 1 - -
      

      3×3

      - - - 1 - - -
      - - 3 - 3 - -
      - 3 - 9 - 3 -
      1 - 9 - 9 - 1
      - 3 - 9 - 3 -
      - - 3 - 3 - -
      - - - 1 - - -
      

      我从 4×4 网格开始,但不,谢谢。起始广场似乎有 36 条通往它的路径,实际上识别它们是很乏味的。在任何情况下,棋子都从图案的中心开始,我们可以根据需要绘制棋盘。

      然而,显然有一种模式,它相当大声疾呼存在数学对称性,但我既没有时间也没有耐心去解决它。每个极点都有一条路径,下一组端点有 n 条路径,下一组似乎有 n2 条路径。我怀疑我在计算 4×4 网格的最里面的一组端点时犯了一个错误,但如果我没有,36 = n(n - 1)2 em>,这强烈暗示了环的模式。

      无论如何,正如我所说,这个问题非常复杂,几乎可以肯定的是,你的方法受到了评判,而不是你的回答能力。不过,这是一个有趣的练习。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-16
        • 1970-01-01
        • 2021-05-11
        • 2012-02-27
        • 2018-04-01
        • 2020-03-28
        相关资源
        最近更新 更多