我有一个概率问题,我需要在合理的时间内进行模拟。简而言之,我有 30 个不公平的硬币,每个硬币都有不同的已知概率。然后我想问诸如“正好有 12 个正面朝上的概率是多少?”或“至少 5 个正面朝上的概率是多少?”。
我知道基本的概率论,所以我知道我可以列举所有(30 个选择 x)的可能性,但这并不是特别可扩展的。最坏的情况(30 选择 15)有超过 1.5 亿种组合。从计算的角度来看,有没有更好的方法来解决这个问题?
非常感谢任何帮助,谢谢!:-)
我有一个概率问题,我需要在合理的时间内进行模拟。简而言之,我有 30 个不公平的硬币,每个硬币都有不同的已知概率。然后我想问诸如“正好有 12 个正面朝上的概率是多少?”或“至少 5 个正面朝上的概率是多少?”。
我知道基本的概率论,所以我知道我可以列举所有(30 个选择 x)的可能性,但这并不是特别可扩展的。最坏的情况(30 选择 15)有超过 1.5 亿种组合。从计算的角度来看,有没有更好的方法来解决这个问题?
非常感谢任何帮助,谢谢!:-)
您可以使用动态编程方法。
例如,要计算 30 枚硬币中有 12 枚正面朝上的概率,设 P(n, k) 是前 n 枚硬币中有 k 枚正面朝上的概率。
那么 P(n, k) = p_n * P(n - 1, k - 1) + (1 - p_n) * P(n - 1, k)
(这里 p_i 是第 i 个硬币是正面的概率)。
您现在可以在动态规划算法中使用此关系。有一个包含 13 个概率的向量(表示 P(n - 1, i) for i in 0..12)。使用上述递归关系为 P(n, i) 构建一个 13 的新向量。重复直到 n = 30。当然,你从向量 (1, 0, 0, 0, ...) 开始,n=0(因为没有硬币,你肯定没有正面)。
使用此算法的最坏情况是 O(n^2) 而不是指数。
这实际上是一个有趣的问题。我受到启发写了一篇关于它的博客文章,详细介绍了公平与不公平的硬币投掷,一直到 OP 的情况,即每枚硬币都有不同的概率。您需要一种称为动态规划的技术来在多项式时间内解决此问题。
一般问题:给定C,一系列n 个硬币p 1到p n其中p i表示第i个硬币正面朝上的概率,抛完所有硬币后k个正面朝上的概率是多少?
这意味着解决以下递归关系:
P ( n , k , C , i ) = p i x P ( n -1, k -1, C , i +1) + (1- p i ) x P ( n , k , C , i +1)
执行此操作的 Java 代码片段是:
private static void runDynamic() {
long start = System.nanoTime();
double[] probs = dynamic(0.2, 0.3, 0.4);
long end = System.nanoTime();
int total = 0;
for (int i = 0; i < probs.length; i++) {
System.out.printf("%d : %,.4f%n", i, probs[i]);
}
System.out.printf("%nDynamic ran for %d coinsin %,.3f ms%n%n",
coins.length, (end - start) / 1000000d);
}
private static double[] dynamic(double... coins) {
double[][] table = new double[coins.length + 2][];
for (int i = 0; i < table.length; i++) {
table[i] = new double[coins.length + 1];
}
table[1][coins.length] = 1.0d; // everything else is 0.0
for (int i = 0; i <= coins.length; i++) {
for (int j = coins.length - 1; j >= 0; j--) {
table[i + 1][j] = coins[j] * table[i][j + 1] +
(1 - coins[j]) * table[i + 1][j + 1];
}
}
double[] ret = new double[coins.length + 1];
for (int i = 0; i < ret.length; i++) {
ret[i] = table[i + 1][0];
}
return ret;
}
这样做是构建一个表格,显示从p i到p n的硬币序列包含k个正面的概率。
有关二项式概率的更深入介绍以及有关如何应用动态规划的讨论,请查看投币、二项式和动态规划。
伪代码:
procedure PROB(n,k,p)
/*
input: n - number of coins flipped
k - number of heads
p - list of probabilities for n-coins where p[i] is probability coin i will be heads
output: probability k-heads in n-flips
assumptions: 1 <= i <= n, i in [0,1], 0 <= k <= n, additions and multiplications of [0,1] numbers O(1)
*/
A = ()() //matrix
A[0][0] = 1 // probability no heads given no coins flipped = 100%
for i = 0 to k //O(k)
if i != 0 then A[i][i] = A[i-1][i-1] * p[i]
for j = i + 1 to n - k + i //O( n - k + 1 - (i + 1)) = O(n - k) = O(n)
if i != 0 then A[i][j] = p[j] * A[i-1][j-1] + (1-p[j]) * A[i][j-1]
otherwise A[i][j] = (1 - p[j]) * A[i][j-1]
return A[k][n] //probability k-heads given n-flips
最坏情况 = O(kn)