ZOJ3582 Back to the Past

概率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;
}


你可能感兴趣的:(ZOJ3582 Back to the Past)