UVALive 2522 Chocolate(概率DP)

  思路:定义DP方程dp[i][j]标记选到第i个巧克力的时候,桌面上还剩下j个巧克力,状态转移有两个方向,dp[i-1][j-1],dp[i-1]lj+1],分别表示桌面上多了一个和消了一个,乘上需要的概率即可。

  注意:这个题目的输入量很大,所以需要优化,首先是n+m是奇数的时候,或者m > c的时候概率是0。 然后就是当n很大的时候,可以知道后面所加的概率越来越小,题目要求精确到三位小数,所以大约1500以后的值就不会影响答案了,可以直接去掉。如果没有这两个优化,很容易超时。dp过程并不难,难得是时间上的优化(而且我的方法也并不好,跑了800ms)。

代码如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 3000
double dp[N][N];
int main()
{
    int c,n,m;
    double cc;
    while(~scanf("%d",&c))
    {
        if(!c) break;
        scanf("%d%d",&n,&m);
        if(m > c || (m+n)%2){puts("0.000"); continue;}
        if(n > 1500){
            n = 1500;
        }
        memset(dp,0,sizeof(dp));
        dp[0][0] = 1.0;
        cc = c*1.0;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 0; j <= c; j++)
            {
                if(j==0) dp[i][0] = dp[i-1][1]*(1/cc);
                else if(j==c) dp[i][c] = dp[i-1][c-1]*(1/cc);
                else
                {
                    dp[i][j] += dp[i-1][j-1]*((c-j+1.0)/(c));
                    dp[i][j] += dp[i-1][j+1]*((j+1.0)/c);
                }
            }
        }
        printf("%.3lf
",dp[n][m]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jifahu/p/5723227.html