POJ 1322 Chocolate 概率DP 近似取值

题目大意:

就是现在一个袋子里装有C种颜色的巧克力每种各无数个, 现在从袋子当中每次拿出一颗巧克力放在桌上,如果桌上有2颗一样颜色的巧克力则吃掉他们, 问取N次之后桌子上正好有M颗巧克力的概率 (N, M <= 1000000, C <= 100)


大致思路:

这题很明显可以找到状态转移方程, 然后就是N的大小问题, 由于N很大但是题目要求的精度只有0.001所以可以减小N的范围来估算, 细节见代码注释


代码如下:

/*
 * Author: Gatevin
 * Created Time:  2014/12/24 14:41:45
 * File Name: Sora_Kasugano.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

/*
 * 如果用dp[i][j]表示拿出i颗巧克力后桌面上剩下j颗巧克力的概率
 * 很明显有dp[i][j] = dp[i - 1][j - 1]*(C - (j - 1))/C + dp[i - 1][j + 1]*(j + 1)/C;
 * 初始时dp[0][0] = 1;
 * 考虑到内存限制需要使用滚动数组
 * 另外如果M > min(C, N), 显然这个情况是不可能的概率为0
 * 如果N - M不是奇数,这N - M颗巧克力不会全部消失, 不会剩下M颗, 此种情况概率为0
 * 既便如此复杂度依旧是O(N*min(N, C)) 对于多组数组显然不可行
 * 考虑到这是一条markov链, 当n达到一定数值的时候精度误差会小于1e-3并且趋于稳定
 * 测试了下对于n > 500 分奇偶取500和501即可
 * 分奇偶有个很明显的原因对于奇数N变成偶数N - M的奇偶性也会变, 很明显要保持N的奇偶性来保持可行性
 */

double dp[510][2];

int main()
{
    int C, N, M;
    while(scanf("%d", &C), C)
    {
        scanf("%d %d", &N, &M);
        if(M > min(C, N) || ((N - M) & 1))
        {
            printf("0.000\n");
            continue;
        }
        if(N > 500) N = (N & 1) + 500;
        for(int i = 0; i <= N; i++) dp[i][0] = dp[i][1] = 0;
        dp[0][0] = dp[0][1] = 1;
        int now = 1;
        for(int i = 1; i <= N; i++)
        {
            now ^= 1;
            for(int j = 0; j <= min(C, N); j++)
                if((i - j) & 1) dp[j][now] = 0;
                else
                {
                    dp[j][now] = 0;
                    if(j + 1 <= min(C, N))
                        dp[j][now] += dp[j + 1][now ^ 1]*(j + 1.0)/C;
                    if(j - 1 >= 0)
                        dp[j][now] += dp[j - 1][now ^ 1]*(C - j + 1.0)/C;
                }
        }
        printf("%.3f\n", dp[M][now]);
    }
        
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值