题意有三个骰子,分别有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;
}
本文介绍了一个涉及三个不同面数骰子的游戏问题,通过动态规划的方法解决了计算达到特定分数所需轮数的期望值问题。文章详细阐述了解题思路,并提供了完整的C++代码实现。
916

被折叠的 条评论
为什么被折叠?



