POJ-1322 Chocolate 动态规划

这题当M=N=0的时候要输出1.000  刚写的时候默认从第二次开始取了.

详见代码:

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;

/*
题意:从一个拥有无限多的盒子中拿出不同颜色的糖果,拿出任何一种颜色的概率都是1/C
     每次拿出来的糖果都放在桌子上,如果有相同颜色的糖果,就把这两颗糖果吃掉.问
     拿了N次后,桌子上面剩余的糖果数量为M的概率是多大 
     
解法:设状态dp[i][j]为选i次后剩余j颗糖果的概率为多大,省略了一维糖果的颜色数,因此
     每次需要重新计算这个dp值,有如下dp方程:
     dp[i][j] = dp[i-1][j-1] * (C-j+1)/C + dp[i-1][j+1] * (j+1)/C
     含义就是从上一次后拿到了一颗不同颜色的糖果,桌子上增加了一颗糖果而来
     或者是拿到了一颗相同颜色的糖果,桌子上减少了一颗糖果而来 
     
     通过牛人的测试,当N大于1000的时候,为偶数就当做1000处理,为奇数的时候就当做
     1001处理,因为N很大之后,仅仅靠小数点的后三位已经反映不去其差别 
*/

int C, M, N; 
double dp[2][1005][105]; 

void DP() {
    memset(dp, 0, sizeof (dp)); 
    dp[1][1][1] = 1.0; // 摸一次一定会得到一个颜色的糖果
    for (int i = 2; i <= N; ++i) {
        int x = i & 1;
        for (int j = 0; j <= C; ++j) {
            if (j - 1 >= 0)
                dp[x][i][j] += dp[!x][i-1][j-1]*(C-j+1)/C;
            if (j + 1 <= C)
                 dp[x][i][j] += dp[!x][i-1][j+1]*(j+1)/C;
        }
    }
} 

int main() {
    while (scanf("%d", &C), C) {
        scanf("%d %d", &N, &M); 
        if (N == 0 && M == 0) { 
            printf("%.3lf\n", 1.);
            continue;
        }
        if ((N&1)^(M&1) || M > C || M > N) {
            printf("%.3lf\n", 0.);
            continue;
        }
        if (N > 1000) {
            N = N & 1 ? 1001 : 1000;
        }
        DP();
        printf("%.3lf\n", dp[N&1][N][M]);
    }
    return 0;    
} 

 

posted @ 2013-01-11 23:21  沐阳  阅读(248)  评论(0编辑  收藏  举报