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; }
继续翻黑书学正解去。。。以上纯属恶搞。。。