📌  相关文章
📜  N投掷硬币中至少获得K头的可能性

📅  最后修改于: 2021-04-28 18:29:54             🧑  作者: Mango

给定N个硬币,任务是找到在同时扔掉所有N个硬币后获得至少K个磁头的概率。
例子 :

Suppose we have 3 unbiased coins and we have to
find the probability of getting at least 2 heads,
so there are 23 = 8 ways to toss these
coins, i.e.,
HHH, HHT, HTH, HTT, THH, THT, TTH, TTT 

Out of which there are 4 set which contain at
least 2 Heads i.e.,
HHH, HHT, HH, THH

So the probability is 4/8 or 0.5

在n个试验中恰好有k个成功的概率,在任何试验中都有成功率p的概率由下式给出:
{\displaystyle \binom{n}{k}p^k(1-p)^{n-k}=^{n}\textrm{c}_{k}(p)^k (1-p)^{n-k}=\frac {n!(p)^k (1-p)^{n-k}}{(k)!(n-k)!}}
因此,概率(至少有4个头)=
{\displaystyle \binom{6}{4}\binom{1}{2}^4\binom{1}{2}^2+\binom{6}{5}\binom{1}{2}^5\binom{1}{2}^1+\binom{6}{6}\binom{1}{2}^6\binom{1}{2}^0}
{\displaystyle =\frac {1}{2^6} \left ( \frac {6!}{4!2!}+ \frac {6!}{5!1!}+ \frac {6!}{6!0!}\right )}
方法1(天真)
天真的方法是将阶乘的值存储在dp []数组中,并在需要时直接调用它。但是这种方法的问题是我们只能将其存储到一定值,否则将导致溢出。
下面是上述方法的实现

C++
// Naive approach in C++ to find probability of
// at least k heads
#include
using namespace std;
#define MAX 21
 
double fact[MAX];
 
// Returns probability of getting at least k
// heads in n tosses.
double probability(int k, int n)
{
    double ans = 0;
    for (int i = k; i <= n; ++i)
 
        // Probability of getting exactly i
        // heads out of n heads
        ans += fact[n] / (fact[i] * fact[n - i]);
 
    // Note: 1 << n = pow(2, n)
    ans = ans / (1LL << n);
    return ans;
}
 
void precompute()
{
    // Preprocess all factorial only upto 19,
    // as after that it will overflow
    fact[0] = fact[1] = 1;
 
    for (int i = 2; i < 20; ++i)
        fact[i] = fact[i - 1] * i;
}
 
// Driver code
int main()
{
    precompute();
 
    // Probability of getting 2 head out of 3 coins
    cout << probability(2, 3) << "\n";
 
    // Probability of getting 3 head out of 6 coins
    cout << probability(3, 6) <<"\n";
 
    // Probability of getting 12 head out of 18 coins
    cout << probability(12, 18);
 
    return 0;
}


Java
// JAVA Code for Probability of getting
// atleast K heads in N tosses of Coins
class GFG {
     
    public static double fact[];
      
    // Returns probability of getting at least k
    // heads in n tosses.
    public static double probability(int k, int n)
    {
        double ans = 0;
        for (int i = k; i <= n; ++ i)
      
            // Probability of getting exactly i
            // heads out of n heads
            ans += fact[n] / (fact[i] * fact[n-i]);
      
        // Note: 1 << n = pow(2, n)
        ans = ans / (1 << n);
        return ans;
    }
      
    public static void precompute()
    {
        // Preprocess all factorial only upto 19,
        // as after that it will overflow
        fact[0] = fact[1] = 1;
      
        for (int i = 2; i < 20; ++i)
            fact[i] = fact[i - 1] * i;
    }
      
    // Driver code
    public static void main(String[] args)
    {
        fact = new double[100];
        precompute();
      
        // Probability of getting 2 head out
        // of 3 coins
        System.out.println(probability(2, 3));
      
        // Probability of getting 3 head out
        // of 6 coins
        System.out.println(probability(3, 6));
      
        // Probability of getting 12 head out
        // of 18 coins
        System.out.println(probability(12, 18));
      
    }
 }
// This code is contributed by Arnav Kr. Mandal


Python3
# Naive approach in Python3
# to find probability of
# at least k heads
 
MAX=21
 
fact=[0]*MAX
 
# Returns probability of
# getting at least k
# heads in n tosses.
def probability(k, n):
    ans = 0
    for i in range(k,n+1):
 
        # Probability of getting exactly i
        # heads out of n heads
        ans += fact[n] / (fact[i] * fact[n - i])
 
    # Note: 1 << n = pow(2, n)
    ans = ans / (1 << n)
    return ans
 
def precompute():
     
    # Preprocess all factorial
    # only upto 19,
    # as after that it
    # will overflow
    fact[0] = 1
    fact[1] = 1
 
    for i in range(2,20):
        fact[i] = fact[i - 1] * i
 
# Driver code
if __name__=='__main__':
    precompute()
 
    # Probability of getting 2
    # head out of 3 coins
    print(probability(2, 3))
 
    # Probability of getting
    # 3 head out of 6 coins
    print(probability(3, 6))
 
    # Probability of getting
    # 12 head out of 18 coins
    print(probability(12, 18))
     
# This code is contributed by
# mits


C#
// C# Code for Probability of getting
// atleast K heads in N tosses of Coins
using System;
 
class GFG
{
     
    public static double []fact;
     
    // Returns probability of getting at least k
    // heads in n tosses.
    public static double probability(int k, int n)
    {
        double ans = 0;
        for (int i = k; i <= n; ++ i)
     
            // Probability of getting exactly i
            // heads out of n heads
            ans += fact[n] / (fact[i] * fact[n - i]);
     
        // Note: 1 << n = pow(2, n)
        ans = ans / (1 << n);
        return ans;
    }
     
    public static void precompute()
    {
        // Preprocess all factorial only upto 19,
        // as after that it will overflow
        fact[0] = fact[1] = 1;
     
        for (int i = 2; i < 20; ++i)
            fact[i] = fact[i - 1] * i;
    }
     
    // Driver code
    public static void Main()
    {
        fact = new double[100];
        precompute();
     
        // Probability of getting 2 head out
        // of 3 coins
        Console.WriteLine(probability(2, 3));
     
        // Probability of getting 3 head out
        // of 6 coins
        Console.WriteLine(probability(3, 6));
     
        // Probability of getting 12 head out
        // of 18 coins
        Console.Write(probability(12, 18));
     
    }
}
// This code is contributed by nitin mittal.


PHP


Javascript


C++
// Dynamic and Logarithm approach find probability of
// at least k heads
#include
using namespace std;
#define MAX 100001
 
// dp[i] is going to store Log ( i !) in base 2
double dp[MAX];
 
double probability(int k, int n)
{
    double ans = 0; // Initialize result
 
    // Iterate from k heads to n heads
    for (int i=k; i <= n; ++i)
    {
        double res = dp[n] - dp[i] - dp[n-i] - n;
        ans += pow(2.0, res);
    }
 
    return ans;
}
 
void precompute()
{
    // Preprocess all the logarithm value on base 2
    for (int i=2; i < MAX; ++i)
        dp[i] = log2(i) + dp[i-1];
}
 
// Driver code
int main()
{
    precompute();
 
    // Probability of getting 2 head out of 3 coins
    cout << probability(2, 3) << "\n";
 
    // Probability of getting 3 head out of 6 coins
    cout << probability(3, 6) << "\n";
 
    // Probability of getting 500 head out of 10000 coins
    cout << probability(500, 1000);
 
    return 0;
}


Java
// Dynamic and Logarithm approach find probability of
// at least k heads
import java.math.*;
class GFG {
     
static int MAX = 100001;
 
// dp[i] is going to store Log ( i !) in base 2
static double dp[] = new double[MAX];
 
static double probability(int k, int n)
{
    double ans = 0.0; // Initialize result
 
    // Iterate from k heads to n heads
    for (int i=k; i <= n; ++i)
    {
        double res = dp[n] - dp[i] - dp[n-i] - n;
        ans += Math.pow(2.0, res);
    }
 
    return ans;
}
 
static void precompute()
{
    // Preprocess all the logarithm value on base 2
    for (int i=2; i < MAX; ++i)
        dp[i] = (Math.log(i)/Math.log(2)) + dp[i-1];
}
 
// Driver code
public static void main(String args[])
{
    precompute();
 
    // Probability of getting 2 head out of 3 coins
    System.out.println(probability(2, 3));
 
    // Probability of getting 3 head out of 6 coins
    System.out.println(probability(3, 6));
 
    // Probability of getting 500 head out of 10000 coins
    System.out.println(probability(500, 1000));
}
 
}


Python3
# Dynamic and Logarithm approach find probability of
# at least k heads
 
from math import log2
MAX=100001
 
# dp[i] is going to store Log ( i !) in base 2
dp=[0]*MAX
 
def probability( k, n):
 
    ans = 0 # Initialize result
 
    # Iterate from k heads to n heads
    for i in range(k,n+1):
 
        res = dp[n] - dp[i] - dp[n-i] - n
        ans = ans + pow(2.0, res)
     
 
    return ans
 
 
def precompute():
 
    # Preprocess all the logarithm value on base 2
    for i in range(2,MAX):
        dp[i] = log2(i) + dp[i-1]
 
 
# Driver code
if __name__=='__main__':
    precompute()
 
    # Probability of getting 2 head out of 3 coins
    print(probability(2, 3))
 
    # Probability of getting 3 head out of 6 coins
    print(probability(3, 6))
 
    # Probability of getting 500 head out of 10000 coins
    print(probability(500, 1000))
 
#this code is contributed by ash264


C#
// Dynamic and Logarithm approach find probability of
// at least k heads
using System;
 
class GFG
{
     
static int MAX = 100001;
 
// dp[i] is going to store Log ( i !) in base 2
static double[] dp = new double[MAX];
 
static double probability(int k, int n)
{
    double ans = 0.0; // Initialize result
 
    // Iterate from k heads to n heads
    for (int i = k; i <= n; ++i)
    {
        double res = dp[n] - dp[i] - dp[n-i] - n;
        ans += Math.Pow(2.0, res);
    }
    return ans;
}
 
static void precompute()
{
    // Preprocess all the logarithm value on base 2
    for (int i = 2; i < MAX; ++i)
        dp[i] = (Math.Log(i) / Math.Log(2)) + dp[i - 1];
}
 
// Driver code
public static void Main()
{
    precompute();
 
    // Probability of getting 2 head out of 3 coins
    Console.WriteLine(probability(2, 3));
 
    // Probability of getting 3 head out of 6 coins
    Console.WriteLine(probability(3, 6));
 
    // Probability of getting 500 head out of 10000 coins
    Console.WriteLine(Math.Round(probability(500, 1000),6));
}
}
 
// This code is contributed by mits


PHP


Javascript


输出:

0.5
0.65625
0.118942

时间复杂度: O(n),其中n <20
辅助空间: O(n)
方法2(动态编程和日志)
另一种方法是使用动态编程和对数。 log()实际上对于存储任何数字的阶乘确实有用,而不必担心溢出。让我们看看如何使用它:

At first let see how n! can be written.
n! = n * (n-1) * (n-2) * (n-3) * ... * 3 * 2 * 1

Now take log on base 2 both the sides as:
=> log(n!) = log(n) + log(n-1) + log(n-2) + ... + log(3) 
         + log(2) + log(1)

Now whenever we need to find the factorial of any number, we can use
this precomputed value. For example:
Suppose if we want to find the value of nCi which can be written as:
=> nCi = n! / (i! * (n-i)! )

Taking log2() both sides as:
=> log2 (nCi) = log2 ( n! / (i! * (n-i)! ) )
=> log2 (nCi) = log2 ( n! ) - log2(i!) - log2( (n-i)! )  `

Putting dp[num] = log2 (num!), we get:
=> log2 (nCi) = dp[n] - dp[i] - dp[n-i] 

But as we see in above relation there is an extra factor of 2n which
tells the probability of getting i heads, so
=> log2 (2n) = n.

We will subtract this n from above result to get the final answer:
=> Pi (log2 (nCi)) = dp[n] - dp[i] - dp[n-i] - n

Now: Pi (nCi) = 2 dp[n] - dp[i] - dp[n-i] - n

Tada! Now the questions boils down the summation of Pi for all i in
[k, n] will yield the answer which can be calculated easily without
overflow.

下面是说明这一点的代码:

C++

// Dynamic and Logarithm approach find probability of
// at least k heads
#include
using namespace std;
#define MAX 100001
 
// dp[i] is going to store Log ( i !) in base 2
double dp[MAX];
 
double probability(int k, int n)
{
    double ans = 0; // Initialize result
 
    // Iterate from k heads to n heads
    for (int i=k; i <= n; ++i)
    {
        double res = dp[n] - dp[i] - dp[n-i] - n;
        ans += pow(2.0, res);
    }
 
    return ans;
}
 
void precompute()
{
    // Preprocess all the logarithm value on base 2
    for (int i=2; i < MAX; ++i)
        dp[i] = log2(i) + dp[i-1];
}
 
// Driver code
int main()
{
    precompute();
 
    // Probability of getting 2 head out of 3 coins
    cout << probability(2, 3) << "\n";
 
    // Probability of getting 3 head out of 6 coins
    cout << probability(3, 6) << "\n";
 
    // Probability of getting 500 head out of 10000 coins
    cout << probability(500, 1000);
 
    return 0;
}

Java

// Dynamic and Logarithm approach find probability of
// at least k heads
import java.math.*;
class GFG {
     
static int MAX = 100001;
 
// dp[i] is going to store Log ( i !) in base 2
static double dp[] = new double[MAX];
 
static double probability(int k, int n)
{
    double ans = 0.0; // Initialize result
 
    // Iterate from k heads to n heads
    for (int i=k; i <= n; ++i)
    {
        double res = dp[n] - dp[i] - dp[n-i] - n;
        ans += Math.pow(2.0, res);
    }
 
    return ans;
}
 
static void precompute()
{
    // Preprocess all the logarithm value on base 2
    for (int i=2; i < MAX; ++i)
        dp[i] = (Math.log(i)/Math.log(2)) + dp[i-1];
}
 
// Driver code
public static void main(String args[])
{
    precompute();
 
    // Probability of getting 2 head out of 3 coins
    System.out.println(probability(2, 3));
 
    // Probability of getting 3 head out of 6 coins
    System.out.println(probability(3, 6));
 
    // Probability of getting 500 head out of 10000 coins
    System.out.println(probability(500, 1000));
}
 
}

Python3

# Dynamic and Logarithm approach find probability of
# at least k heads
 
from math import log2
MAX=100001
 
# dp[i] is going to store Log ( i !) in base 2
dp=[0]*MAX
 
def probability( k, n):
 
    ans = 0 # Initialize result
 
    # Iterate from k heads to n heads
    for i in range(k,n+1):
 
        res = dp[n] - dp[i] - dp[n-i] - n
        ans = ans + pow(2.0, res)
     
 
    return ans
 
 
def precompute():
 
    # Preprocess all the logarithm value on base 2
    for i in range(2,MAX):
        dp[i] = log2(i) + dp[i-1]
 
 
# Driver code
if __name__=='__main__':
    precompute()
 
    # Probability of getting 2 head out of 3 coins
    print(probability(2, 3))
 
    # Probability of getting 3 head out of 6 coins
    print(probability(3, 6))
 
    # Probability of getting 500 head out of 10000 coins
    print(probability(500, 1000))
 
#this code is contributed by ash264

C#

// Dynamic and Logarithm approach find probability of
// at least k heads
using System;
 
class GFG
{
     
static int MAX = 100001;
 
// dp[i] is going to store Log ( i !) in base 2
static double[] dp = new double[MAX];
 
static double probability(int k, int n)
{
    double ans = 0.0; // Initialize result
 
    // Iterate from k heads to n heads
    for (int i = k; i <= n; ++i)
    {
        double res = dp[n] - dp[i] - dp[n-i] - n;
        ans += Math.Pow(2.0, res);
    }
    return ans;
}
 
static void precompute()
{
    // Preprocess all the logarithm value on base 2
    for (int i = 2; i < MAX; ++i)
        dp[i] = (Math.Log(i) / Math.Log(2)) + dp[i - 1];
}
 
// Driver code
public static void Main()
{
    precompute();
 
    // Probability of getting 2 head out of 3 coins
    Console.WriteLine(probability(2, 3));
 
    // Probability of getting 3 head out of 6 coins
    Console.WriteLine(probability(3, 6));
 
    // Probability of getting 500 head out of 10000 coins
    Console.WriteLine(Math.Round(probability(500, 1000),6));
}
}
 
// This code is contributed by mits

的PHP


Java脚本


输出:

0.5
0.65625
0.512613