题意:
给定每个题可以解出(独立和偷听)的概率,求解出0~12题的概率。
思路:
首先可以算出每个题解出的概率,即1-解不出该题的概率,即
///计算独立的每道题解出来的概率
for(int i=1;i<=12;i++){
double tmp=(1-a[i])*(1-b[i])*(1-c[i]);
ac[i]=1-tmp;
} 再考虑如何计算解出0~12题的概率。因为数据范围很友好,可以用dfs或状压枚举或dp。
思路一:DP
考虑用dp[i] [j]表示只做前i个题做对了j个题的概率。那么很容易可以推出分界点就是第i个题是否做对。
如果第i个题做不对,那么dp[i] [j]就可以由dp[i-1] [j]转移而来。
如果第i个题做的对,那么dp[i] [j]就可以由dp[i-1] [j-1]转移而来。
即
dp[i][j]=dp[i-1][j]*(1-ac[i])+dp[i-1][j-1]*ac[i];
要注意初始化dp[0] [0] =1,表示前0个题做对0个题的概率是1
以及转移过程中对j==0的特殊处理。
完整代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn=15;
double a[maxn],b[maxn],c[maxn];
double dp[maxn][maxn];
double ac[maxn];///一道题解出来的概率
int main(){
for(int i=1;i<=12;i++) cin>>a[i];
for(int i=1;i<=12;i++) cin>>b[i];
for(int i=1;i<=12;i++) cin>>c[i];
///dp[i][j]表示只做前i个题做对了j个题的概率
///计算独立的每道题解出来的概率
for(int i=1;i<=12;i++){
double tmp=(1-a[i])*(1-b[i])*(1-c[i]);
ac[i]=1-tmp;
}
dp[0][0]=1;
for(int i=1;i<=12;i++){
dp[i][0]=dp[i-1][0]*(1-ac[i]);
for(int j=1;j<=i;j++){
dp[i][j]=dp[i-1][j]*(1-ac[i])+dp[i-1][j-1]*ac[i];
}
}
for(int i=0;i<=12;i++){
printf("%.6f\n",dp[12][i]);
}
return 0;
} 思路二:状压枚举
用二进制数表示每道题是否解出的状态,在每一种状态下枚举每一道题是否被解出,计算相应的概率即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=15;
double a[maxn],b[maxn],c[maxn];
double dp[maxn];
double ac[maxn];///一道题解出来的概率
int main(){
for(int i=0;i<12;i++) cin>>a[i];
for(int i=0;i<12;i++) cin>>b[i];
for(int i=0;i<12;i++) cin>>c[i];
///计算独立的每道题解出来的概率
for(int i=0;i<12;i++){
double tmp=(1-a[i])*(1-b[i])*(1-c[i]);
ac[i]=1-tmp;
}
for(int i=0;i<(1<<12);i++){
int tmp=0;
double tt=1;
for(int j=0;j<12;j++)
if((1<<j)&i){
tmp++;
tt*=ac[j];
}
else tt*=(1-ac[j]);
dp[tmp]+=tt;
}
for(int i=0;i<=12;i++)
printf("%.6f\n",dp[i]);
return 0;
} 思路三:DFS
跟状压枚举的思路基本一致,只是换了种实现形式。具体可参考:传送门

京公网安备 11010502036488号