通过以p%概率抛掷一枚金属硬币来打开所有n个灯泡所需的预期移动次数?

时间:2017-02-20 19:38:34

标签: probability

有n个灯泡。最初,每个灯泡都关闭。在每次移动中,您可以选择一个随机灯泡(选择每个灯泡的概率相同)。如果灯泡已打开,则不执行任何操作。如果灯泡关闭,你必须掷硬币。如果它是头部,你可以打开灯泡,但如果它是尾部,灯泡将保持关闭状态。

为了使问题更加无聊,硬币不是一个公平的硬币,落尾的机会是p%。

打开所有灯泡所需的预期移动次数是多少?

1 个答案:

答案 0 :(得分:0)

天真的方法:蒙特卡罗模拟

描述

(您没有提供任何关于您想要的解决方案的信息,因此我提出了可能最简单但功能最强大的方法:模拟)

Monte-Carlo方法允许我们模拟这个随机过程并观察所需的步骤数。由于这只是一个嘈杂的估计,我们需要多次这样做。使用无限次运行,此解决方案将收敛到理论解决方案!

代码

这是一些简单的基于python的代码:

import random
import matplotlib.pyplot as plt  # just for plotting

n = 10
p = 0.7
n_samples = 1000000

def run():
    states = [0 for i in range(n)]
    steps = 0
    while 0 in states:
        index = random.randint(0, n-1)
        if random.random() < p:        # non-fair coin
            states[index] = 1
        steps += 1
    return steps

avg = 0.0
samples = []
for sample in range(n_samples):
    steps = run()
    avg += steps
    samples.append(steps)

print(avg / n_samples)
plt.hist(samples)
plt.show()

代码输出

41.853233

enter image description here

数学方法:吸收马尔可夫链

描述

由于描述灯泡状态变化的概率仅取决于当前状态,马尔可夫假设是有效的,我们可以使用 Markov-Chains 获得所需的平均步数。

因为最终状态将永远自我循环,并且因为它将在给定无限步数的情况下达到,所以这是吸收马尔可夫链

由于所有灯泡都是相同的,我们不需要模拟过渡,其中每个激活的灯泡组合相互映射。我们可以将它简化为更简单的:0灯泡 - &gt; 1个灯泡 - &gt; ......(当然还有自我循环)。

离散时间离散状态空间吸收马尔可夫链允许简单而有力地计算所需值。

wikipedia解释了一些理论。它也是以下代码使用的公式的来源。

代码

再一些python:

import numpy as np

N = 10
P = 0.7

""" Build transition matrix """
trans_mat = np.zeros((N+1, N+1))
for source_state in range(N):
    prob_hitting_next = ((N-source_state) / float(N)) * P
    inverse = 1.0 - prob_hitting_next
    trans_mat[source_state, source_state] = inverse
    trans_mat[source_state, source_state+1] = prob_hitting_next
trans_mat[N, N] = 1.0

""" Will look like this:
[[ 0.3   0.7   0.    0.    0.    0.    0.    0.    0.    0.    0.  ]
 [ 0.    0.37  0.63  0.    0.    0.    0.    0.    0.    0.    0.  ]
 [ 0.    0.    0.44  0.56  0.    0.    0.    0.    0.    0.    0.  ]
 [ 0.    0.    0.    0.51  0.49  0.    0.    0.    0.    0.    0.  ]
 [ 0.    0.    0.    0.    0.58  0.42  0.    0.    0.    0.    0.  ]
 [ 0.    0.    0.    0.    0.    0.65  0.35  0.    0.    0.    0.  ]
 [ 0.    0.    0.    0.    0.    0.    0.72  0.28  0.    0.    0.  ]
 [ 0.    0.    0.    0.    0.    0.    0.    0.79  0.21  0.    0.  ]
 [ 0.    0.    0.    0.    0.    0.    0.    0.    0.86  0.14  0.  ]
 [ 0.    0.    0.    0.    0.    0.    0.    0.    0.    0.93  0.07]
 [ 0.    0.    0.    0.    0.    0.    0.    0.    0.    0.    1.  ]]
"""

""" Q:      the sub-matrix of trans_mat without
            the rows and columns of any absorbing states
    N_fund: fundamental matrix
    t:      expected number of steps before beeing absorved for each start-state
"""
Q_sub = trans_mat[:N, :N]
N_fund = np.linalg.inv(np.eye(N) - Q_sub)
t = np.dot(N_fund, np.ones(N))
print(t)
print(t[0])  # this is the value we want

代码输出

[ 41.84240363  40.4138322   38.82653061  37.04081633
  35. 32.61904762 29.76190476  26.19047619  21.42857143  14.28571429]

41.8424036281   # less than 1 second calculation time!