Это действительно интересная проблема. Я был вдохновлен, чтобы написать сообщение в блоге об этом, детально освещающем справедливые против несправедливых подбрасываний монеты вплоть до ситуации, когда ОП имел различную вероятность для каждой монеты. Для решения этой проблемы за полиномиальное время вам понадобится метод динамического программирования.
Общая проблема: Дано 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 , к , C , я * * + одна тысяча семьдесят-шесть 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 голов.
Для более глубокого знакомства с биномиальной вероятностью и обсуждения того, как применять динамическое программирование, взгляните на Брошюры монет, биномы и динамическое программирование .