ZOJ 3329 One Person Game

题意有三个骰子,分别有k1,k2,k3面,每个面等概率,现在同时投三个骰子,如果第一个为a,第二个为b,第三个为c,直接将总和置为0,否则就在总和上加上三个骰子的和,问要使总和大于n要多少轮的期望为多少。

看了kuangbin的题解,明白了很多。

定义dp[i] 当前总和为 i 到结束的期望次数。

dp[i]=∑(pk*dp[i+k])+dp[0]*p0+1;

你发现这个问题变成了一个环,递归下去,没办法解决。

但是,因为每次都是只和dp[0]有关,所以可以把系数分解出来。

那么就有了 dp[i] = A[i]*dp[0] + B[i]

然后再代入原式,得到A[i] 和 B[i],发现 A, B都是可以dp求解的,最后dp[0]也就求出来了。

/*************************************************************************
    > File Name: source.cpp
    > Author: oldflag
    > Created Time: 星期一 10/ 3 22:27:45 2016
 ************************************************************************/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <cstdlib>
#include <stack>
#include <queue>
using namespace std;
typedef long long LL;

int k1, k2, k3;
int a, b, c;
int sum;
int n;
double p[37];
double p0;
double A[550];
double B[550];
int main()
{
//	freopen("data.vim", "r", stdin);
	int T;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d", &n);
		scanf("%d%d%d", &k1, &k2, &k3);
		scanf("%d%d%d", &a, &b, &c);
		sum = k1 + k2 + k3;
		p0 = 1.0/k1/k2/k3;
		memset(p, 0, sizeof p);
		memset(A, 0, sizeof A);
		memset(B, 0, sizeof B);
		for(int i = 1; i <= k1; i++)
		{
			for(int j = 1; j <= k2; j++)
			{
				for(int k = 1; k <= k3; k++)
				{
					if(i == a && j == b && k == c) continue;
					p[i + j + k] += p0;
				}
			}
		}
		for(int i = n; i >= 0; i--)
		{
			A[i] = p0;
			B[i] = 1;
			for(int j = 3; j <= sum; j++)
			{
				A[i] += p[j]*A[i + j];
				B[i] += p[j]*B[i + j];
			}
		}
		printf("%.16lf\n", B[0]/(1 - A[0])); 
	}
    return 0;
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值