有n个灯泡。最初,每个灯泡都关闭。在每次移动中,您可以选择一个随机灯泡(选择每个灯泡的概率相同)。如果灯泡已打开,则不执行任何操作。如果灯泡关闭,你必须掷硬币。如果它是头部,你可以打开灯泡,但如果它是尾部,灯泡将保持关闭状态。
为了使问题更加无聊,硬币不是一个公平的硬币,落尾的机会是p%。
打开所有灯泡所需的预期移动次数是多少?
答案 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
由于描述灯泡状态变化的概率仅取决于当前状态,马尔可夫假设是有效的,我们可以使用 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!