Given an array p[] of odd length N where p[i] denotes the probability of getting a head on the ith coin. As the coins are biased, the probability of getting a head is not always equal to 0.5. The task is to find the probability of getting heads more number of times than tails.
Examples:
Input: p[] = {0.3, 0.4, 0.7}
Output: 0.442
Probability for a tail = (1 – Probability for a head)
For heads greater than tails, there are 4 possibilities:
P({head, head, tail}) = 0.3 x 0.4 x (1 – 0.7) = 0.036
P({tail, head, head}) = (1 – 0.3) x 0.4 x 0.7 = 0.196
P({head, tail, head}) = 0.3 x (1 – 0.4) x 0.7= 0.126
P({head, head, head}) = 0.3 x 0.4 x 0.7 = 0.084
Adding the above probabilities
0.036 + 0.196 + 0.126 + 0.084 = 0.442
Input: p[] = {0.3, 0.5, 0.2, 0.6, 0.9}
Output: 0.495
Naive approach: The naive approach would be creating all the 2n possibilities of heads and tails. Then calculating the probabilities for different permutations and adding them when the number of heads are greater than the number of tails just like the example explanation. This would give TLE when n is large.
Efficient approach: The idea is to use dynamic programming. Let’s assume dp[i][j] to be the probability of getting j heads with first i coins. To get j heads at the ith position, there are two possibilities:
- If number of heads till (i – 1) coins is equal to j then a tail comes at ith.
- If number of heads till (i – 1) coins is equal to (j – 1) then a head comes at ith position
Hence, it can be broken into its subproblems as follows:
dp[i][j] = dp[i – 1][j] * (1 – p[i]) + dp[i – 1][j – 1] * p[i]
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
double Probability( double p[], int n)
{
double dp[n + 1][n + 1];
memset (dp, 0.0, sizeof (dp));
dp[0][0] = 1.0;
for ( int i = 1; i <= n; i += 1) {
for ( int j = 0; j <= i; j += 1) {
if (j == 0)
dp[i][j] = dp[i - 1][j]
* (1.0 - p[i]);
else
dp[i][j] = dp[i - 1][j]
* (1.0 - p[i])
+ dp[i - 1][j - 1] * p[i];
}
}
double ans = 0.0;
for ( int i = (n + 1) / 2; i <= n; i += 1)
ans += dp[n][i];
return ans;
}
int main()
{
double p[] = { 0.0, 0.3, 0.4, 0.7 };
int n = sizeof (p) / sizeof (p[0]) - 1;
cout << Probability(p, n);
return 0;
}
|
Java
import java.io.*;
class GFG
{
static double Probability( double p[], int n)
{
double [][]dp = new double [n + 1 ][n + 1 ];
dp[ 0 ][ 0 ] = 1.0 ;
for ( int i = 1 ; i <= n; i += 1 )
{
for ( int j = 0 ; j <= i; j += 1 )
{
if (j == 0 )
dp[i][j] = dp[i - 1 ][j]
* ( 1.0 - p[i]);
else
dp[i][j] = dp[i - 1 ][j]
* ( 1.0 - p[i])
+ dp[i - 1 ][j - 1 ] * p[i];
}
}
double ans = 0.0 ;
for ( int i = (n + 1 ) / 2 ; i <= n; i += 1 )
ans += dp[n][i];
return ans;
}
public static void main(String[] args)
{
double p[] = { 0.0 , 0.3 , 0.4 , 0.7 };
int n = p.length - 1 ;
System.out.println(Probability(p, n));
}
}
|
Python3
import numpy as np
def Probability(p, n) :
dp = np.zeros((n + 1 , n + 1 ));
for i in range (n + 1 ) :
for j in range (n + 1 ) :
dp[i][j] = 0.0
dp[ 0 ][ 0 ] = 1.0 ;
for i in range ( 1 , n + 1 ) :
for j in range (i + 1 ) :
if (j = = 0 ) :
dp[i][j] = dp[i - 1 ][j] * ( 1.0 - p[i]);
else :
dp[i][j] = (dp[i - 1 ][j] * ( 1.0 - p[i]) +
dp[i - 1 ][j - 1 ] * p[i]);
ans = 0.0 ;
for i in range ((n + 1 ) / / 2 , n + 1 ) :
ans + = dp[n][i];
return ans;
if __name__ = = "__main__" :
p = [ 0.0 , 0.3 , 0.4 , 0.7 ];
n = len (p) - 1 ;
print (Probability(p, n));
|
C#
using System;
class GFG
{
static double Probability( double []p, int n)
{
double [,]dp = new double [n + 1, n + 1];
dp[0, 0] = 1.0;
for ( int i = 1; i <= n; i += 1)
{
for ( int j = 0; j <= i; j += 1)
{
if (j == 0)
dp[i,j] = dp[i - 1,j]
* (1.0 - p[i]);
else
dp[i,j] = dp[i - 1,j]
* (1.0 - p[i])
+ dp[i - 1,j - 1] * p[i];
}
}
double ans = 0.0;
for ( int i = (n + 1) / 2; i <= n; i += 1)
ans += dp[n,i];
return ans;
}
static public void Main ()
{
double []p = { 0.0, 0.3, 0.4, 0.7 };
int n = p.Length - 1;
Console.Write(Probability(p, n));
}
}
|
Javascript
<script>
function Probability(p , n)
{
var dp = Array(n + 1).fill(0).map(
x => Array(n + 1).fill(0));
dp[0][0] = 1.0;
for ( var i = 1; i <= n; i += 1)
{
for ( var j = 0; j <= i; j += 1)
{
if (j == 0)
dp[i][j] = dp[i - 1][j] *
(1.0 - p[i]);
else
dp[i][j] = dp[i - 1][j] * (1.0 - p[i]) +
dp[i - 1][j - 1] * p[i];
}
}
var ans = 0.0;
for ( var i = parseInt((n + 1) / 2); i <= n; i += 1)
ans += dp[n][i];
return ans;
}
var p = [ 0.0, 0.3, 0.4, 0.7 ];
var n = p.length - 1;
document.write(Probability(p, n));
</script>
|
Time complexity: O(n2), where n is the size of the given array.
Auxiliary space: O(n2) because using extra space for array dp