概率求期望入门推荐文章:
http://kicd.blog.163.com/blog/static/126961911200910168335852/
题意:(有环、倒推)
投掷3枚骰子,如果dice1 = a,dice2 = b,dice3 = c。那么你的点数置为0,否则加上这三枚点数之和。
问你点数最终超过n,所需要投掷次数的期望。
思路:
正如我们所见,这个期望是有环的,就是可以可以回到0,因此我们需要进行式子替换。
dp[i]:从i出发,到游戏结束所需要投掷骰子次数的期望。
引用一下别人的blog:(http://blog.csdn.net/xingyeyongheng/article/details/25639827)
(1):dp[i]=SUM(p[k]*dp[i+k])+p[0]*dp[0]+1;//p[k]表示增加分数为k的概率,p[0]表示分数变为0的概率
假定
(2):dp[i]=A[i]*dp[0]+B[i];
则
(3):dp[i+k]=A[i+k]*dp[0]+B[i+k];
将(3)代入(1)得:
(4):dp[i]=(SUM(p[k]*A[i+k])+p[0])*dp[0]+SUM(p[k]*B[i+k])+1;
将4与2做比较得:
A[i]=(SUM(p[k]*A[i+k])+p[0]);
B[i]=SUM(p[k]*B[i+k])+1;
当i+k>n时A[i+k]=B[i+k]=0可知
所以dp[0]=B[0]/(1-A[0])可求出
code:
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <iomanip>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXN = 550;
double a[MAXN], b[MAXN], dp[MAXN];
double p[30];
int main()
{
ios::sync_with_stdio(false);
int T;
int n, k1, k2, k3, A, B, C;
while(cin>>T)
{
while(T--)
{
cin>>n>>k1>>k2>>k3>>A>>B>>C;
double t = 1.0/(k1*k2*k3);
//get the Matrix p;
memset(p, 0, sizeof(p));
p[0] = t;
for(int i = 1;i <= k1; i++)
for(int j = 1;j <= k2; j++)
for(int z = 1;z <= k3; z++)
p[i+j+z] += t;
//get the Matrix a, b;
p[A+B+C] -= p[0];
int tot = k1+k2+k3;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
for(int tn = n; tn >= 0; tn--)
{
a[tn] = p[0];
b[tn] = 1;
for(int i = 3;i <= tot; i++)
{
if(p[i] != 0)
{
a[tn] += a[tn+i] * p[i];
b[tn] += b[tn+i] * p[i];
}
}
}
//get the dp[0];
//cout<<"a[0] = "<<a[0]<<endl;
//cout<<"b[0] = "<<b[0]<<endl;
double res = b[0]/(1-a[0]);
cout<<fixed<<setprecision(8)<<res<<endl;
}
}
return 0;
}