poj 1322 Chocolate 概率DP

  状态 dp( i, j ) 表示 拿出i块巧克力,桌面上剩余j块的概率

  若再拿出一块巧克力,则可能出现两种情况

    一,一种是,从 桌面已出现的 J 种取 一种,然后被吃掉,则桌面总数量减少1,得到状态 dp(I+1,J-1),概率为 DP(I,J)*J/C,

    二,一种是,从 桌面上未出现的C-J种取 一种,然后桌面数量增加一个,得到状态DP(I+1,J+1),概率为DP(I,J)*(C-J)/C

  注意到 第一种情形出现的条件是 J-1 >= 0 ,第二种出现条件为 J+1 <= C

  另外,我们知道当 M 》 C ,以及 M,N奇偶性不同时,概率必定为0.

  至于N = 1e7, C = 100, 因为我们只需要相邻的两种状态,所以可以用滚动数组来优化空间。

  实际上这样还不行。。有一条神级剪枝。。我也不知道为毛。。。黑书上259页是用 生成函数来解

这里贴上奇葩AC代码,仅限定与C++提交才可AC

View Code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

const int N = 1e6+10;

double dp[2][110];

int main()
{
    int C, n, m;
    while( scanf("%d", &C) !=  EOF)
    {
        if( C == 0 ) break;
        scanf("%d%d", &n,&m);
        if( m > C || ( (n&1) != (m&1) ) ) printf("0.000\n");
        else
        {
            if( n >= 1000 ){     //神剪枝,无法理解
                if(n&1) n = 1001;
                else    n = 1000;
            }    
            int cur = 0;
            memset( dp, 0, sizeof(dp));    
            dp[0][0] = 1;
            for(int i = 1; i <= n; i++)
            {
                memset( dp[!cur], 0, sizeof(dp[!cur]));    
                for(int j = 0; j <= C; j++)
                {
                    if( j-1 >= 0 )  dp[!cur][j] += dp[cur][j-1]*(1.0*(C+1-j)/C);
                    if( j+1 <= C  ) dp[!cur][j] += dp[cur][j+1]*(1.0*(j+1)/C);
                }
                cur = !cur;    
            }
            printf("%.3lf\n", dp[cur][m] );
        }
    }
    return 0;
}

继续翻黑书学正解去。。。以上纯属恶搞。。。

原文地址:https://www.cnblogs.com/yefeng1627/p/2857123.html