ZOJ3582 Back to the Past

来源:互联网 发布:华为面试 知乎 编辑:程序博客网 时间:2024/04/28 00:48

概率DP

用dp[i][j]表示当前两边分别有i和j个亮的,此时到目标的期望。有:

dp[i][j] = 0 (i >= m && j >= m)

dp[i][j] = 1 + sigma(dp[i+a][j+b] * p) ,a>=0 && b>=0,p根据组合数算一下就行了,带环移项消一下也就行了

幸好这题对精度要求不太高= =


#include <cstdio>#include <cstring>#include <cctype>#include <cstdlib>#include <ctime>#include <climits>#include <cmath>#include <iostream>#include <string>#include <vector>#include <set>#include <map>#include <list>#include <queue>#include <stack>#include <deque>#include <algorithm>using namespace std;const int maxn = 55;int m ,n;double p, q, pp[maxn], qq[maxn];double c[maxn][maxn];double dp[maxn][maxn];int main(){    for (int i=0;i<maxn;i++) c[i][0] = c[i][i] = 1;    for (int i=2;i<maxn;i++)        for (int j=1;j<i;j++)            c[i][j] = c[i-1][j-1] + c[i-1][j];    while (scanf("%d%d%lf", &n, &m, &p) == 3 && n)    {        if (p == 1) {printf("1.000000\n"); continue;}        q = 1 - p;        pp[0] = 1;        for (int i=1;i<=n;i++) pp[i] = pp[i-1] * p;        qq[0] = 1;        for (int i=1;i<=n;i++) qq[i] = qq[i-1] * q;        for (int i=n;i>=0;i--)            for (int j=n;j>=0;j--)            {                if (i >= m && j >= m) {dp[i][j] = 0; continue;}                dp[i][j] = 1;                for (int ii=0;i+ii<=n;ii++)                    for (int jj=0;j+jj<=n;jj++)                    {                        if (ii == 0 && jj == 0) continue;                        dp[i][j] += dp[i+ii][j+jj] * c[n-i][ii] * pp[ii] * qq[n-i-ii] * c[n-j][jj] * pp[jj] * qq[n-j-jj];                    }                dp[i][j] /= (1 - qq[n-i] * qq[n-j]);                //printf("%d %d : %lf\n", i, j, dp[i][j]);            }        printf("%.6lf\n", dp[0][0]);    }return 0;}