POJ 1322 Chocolate
http://poj.org/problem?id=1322
题目大意:c种颜色的巧克力,拿出n块,桌子上有m块的概率是多少。如果桌子上出现相同颜色的巧克力那么将2块都吃掉
分析:
1》台上的巧克力数和当前拿出的巧克力的颜色有关系,设dp[i][j]表示拿出第i块的时候台上有j块巧克力的概率。巧克力i的颜色有两种情况:与桌上的巧克力颜色相同或者是与桌上的巧克力颜色不同
状态转移方程为:dp[i][j]=dp[i-1][j-1]*p1+dp[i-1][j+2]*p2;
p1=(c-j+1)/c, p2=(j+1)/c;
2》状态i仅和i-1有关,可以进行空间上的优化,用滚动数组实现
3》当拿出2*n+1奇数次巧克力,有k次出现同色,最后剩2*n+1-2*k=2*(n-k)+1,即桌子上剩余奇数个
当拿出2*n偶数次巧克力,有k次出现同色,最后剩2*n-2*k=2*(n-k),即桌上剩余偶数个
因此当(i+j)%2=1的时候,dp[i][j]=0.因为不可能出现拿奇数次桌上剩余偶数个和拿偶数次桌上剩余奇数个的情况
4》dp[0][0]=1.0
5》第一次提交直接超时了, 数据很多,当区域一个较大值后概率区域稳定了 .n>500 n=500+(n%2) 32MS n>300会wa掉
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> double dp[2][102]; int main() { int n, m, c, i, j; while(scanf("%d", &c)!=EOF) { if(c==0) break; scanf("%d%d", &n, &m); if(m>c||m>n||(m+n)%2==1) { printf("0.000\n"); continue; } memset(dp, 0, sizeof(dp)); dp[0][0]=1.0; int t=1; if(n>400) n=(n%2==0)?400:401; for(i=1; i<=n; i++) { for(j=0; j<=c&&j<=i; j++) { if((i+j)%2==1) {dp[t][j]=0; continue; } double p1=(c-j+1)*1.0/c, p2=(j+1)*1.0/c; dp[t][j]=0.0; if(j-1>=0) dp[t][j]+=dp[1-t][j-1]*p1; if(j+1<=i) dp[t][j]+=dp[1-t][j+1]*p2; } t=1-t; } printf("%.3lf\n", dp[n%2][m]); } return 0; }