一开始以为求第0-12个问题的解决概率懵逼了很久

一道简单的概率dp/dfs问题

我们先求出每个问题的解决概率。

我们运用正难则反的思想,先求出我们不能解决第i个问题的概率,即:

然后,用1减去这个概率就是第i个题可以解决的概率了,设为

那么,现在就可以随便乱搞了。

注意到,n很小,可以直接dfs搞,每个点成功和失败都枚举一次,复杂度

还有更优秀的就是用概率dp来解决。

我们设表示前i个问题中,对了j个问题的概率。初始化

那么,直接类似0/1背包转移即可(需要注意的是,这里不能直接转移,还要乘上失败概率)

那么就有转移方程:

【因为这个情况第i个问题不可能成功,所以单独讨论】

【分第i个问题成功和失败两个情况考虑即可】

最后输出即可,复杂度

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=13;
double a[N],b[N],c[N],d[N];
double dp[N][N];
int main(){
    for(int i=1;i<=12;++i){
        scanf("%lf",&a[i]);
    }
    for(int i=1;i<=12;++i){
        scanf("%lf",&b[i]);
    }
    for(int i=1;i<=12;++i){
        scanf("%lf",&c[i]);
    }
    for(int i=0;i<=12;++i){
        d[i]=(1-a[i])*(1-b[i])*(1-c[i]);
        d[i]=1-d[i];
    }
    dp[0][0]=1;
    for(int i=1;i<=12;++i){
        dp[i][0]=dp[i-1][0]*(1-d[i]);
        for(int j=1;j<=i;++j){
            dp[i][j]=dp[i-1][j]*(1-d[i])+dp[i-1][j-1]*d[i];
        }
    }
    for(int i=0;i<=12;++i){
        printf("%.6lf\n",dp[12][i]);
    }
    return 0;
}