poj1322 Chocolate

题意:包里有无穷多个巧克力,巧克力有c种颜色,每次从包里拿出不同颜色巧克力的概率都是相等的,桌面的巧克力不允许颜色相同,若某次拿出的巧克力与桌上的巧克力颜色相同了,则将两颗巧克力都吃掉。计算进行n次拿巧克力的操作后,桌上有m颗巧克力的概率,输出结果精确到小数点后三位。

用dp[ i ][ j ] 表示进行 i 次操作后桌面上有 j 颗巧克力的概率,状态转移方程:dp[ i ][ j ] += dp[ i - 1 ][ j - 1 ] * ( ( c - j + 1.0 ) / c ) + dp[ i - 1 ][ j + 1 ] *( ( j + 1.0 ) / c );

方程的前半部分表示新拿出的巧克力与桌面没有相同颜色, 后半部分表示有相同颜色并吃掉了相同颜色的两颗。

由方程可以看出,第 i 行仅与 i - 1行有关,所以可用滚动数组。

由于dp[ 1 ][ 0 ] = 0 (客观事实), 再根据状态转移方程知:当i + j为奇数时,dp[ i ][ j ] == 0,因为不可能拿奇数次让桌上有偶数颗,也不可能拿偶数次让桌上有奇数颗。

以前不知道有这样的处理方式,数据很大,根据输出为近似值直接压缩了数据,只要满足输出即可。 

#include <iostream>
using namespace std;

double dp[2][102];

int main()
{
	int c, n, m, i, j;

	while(scanf("%d", &c) && c)
	{
		scanf("%d %d", &n, &m);
		if(m > n || m > c || (m + n) % 2){
		    printf("0.000\n");
			continue;
		}
		if(n > 1001)
			n = n % 2 ? 1001 : 1000;
		
		memset(dp, 0, sizeof(dp));
        dp[0][0] = 1.0;
        for(i = 1; i <= n; i++){
			for(j = 0; j <= i && j <= c; j++){
				dp[i%2][j] = 0.0;
				if((i + j) % 2) continue;
				if(j > 0)
			        dp[i%2][j] += dp[1-i%2][j-1] * ((c-j+1.0)*1.0/c);
				if(j+1 <= i-1)
					dp[i%2][j] += dp[1-i%2][j+1] * ((j+1.0)*1.0/c);
			}
		}
		printf("%.3lf\n", dp[n%2][m]);
	}
	return 0;
}





 

另外一种处理方式,当继续拿确定答案几乎不变时,就跳出,不一定要真的进行题目要求的那么多次取巧克力操作。

以下代码 转自:http://hi.baidu.com/ycdoit/blog/item/e961083a0755d5f114cecb93.html

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;

const unsigned int MaxN = 101;
double A[2][MaxN];
const double eps = 0.0000001;
unsigned int C, N, M;
double pre;

double solve()
{
    if (M > C || M > N || (M + N ) % 2 == 1)    return 0.0;
    memset(A, 0, sizeof(A));
    int i, j;
    pre = -1;

    A[0][0] = 1.0;
    for (i = 1; i <= N; ++i)
        for (j = 0; j <= i && j <= C; ++j)
        {
            if ((i + j)% 2 == 1)    continue;
            A[i % 2][j] = 0.0;
            if (j - 1 >= 0)        A[i % 2][j] += A[(i + 1) % 2][j - 1] * (C - j + 1.0) / C;
            if (j + 1 <= i)        A[i % 2][j] += A[(i + 1) % 2][j + 1] * (j + 1.0) / C;
            if ( j == M )
            {
                if ( fabs(A[i%2][j] - pre) < eps)    return pre;
                else pre = A[i%2][j];
            }
        }
    return A[N % 2][M];
}

int main()
{
    while ( scanf("%d", &C), C)
    {
        scanf("%d%d", &N, &M);
        printf("%.3f\n", solve());
    }
    return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值