题目描述
题目大意:有3个筛子,分别有k1,k2,k3面,掷出每一面的概率相同。如果掷出a,b,c那么分数归零,否则分数+(a+b+c),问达到分数n的期望步数。
题解:概率与期望DP
非常经典的题目,一般针对这种成环的题,可以用高斯消元来求解。但是因为这道题只会回到n,所以我们可以通过列式子,画式子巧妙的求解。
dp[i]=sigma(j=1..k1+k2+k3)p[j]*dp[i+j]+dp[0]*p[0]+1
设dp[0]=A[0]*dp[0]+1
对应的我们将上面所有的式子多转换成dp[i]=A[i]*dp[0]+B[i]的形式
那么转移的式子就变成了:
dp[i]=sigma(j=1..k1+k2+k3)p[j]*(A[j+i]*dp[0]+B[j+i]) +dp[0]*p[0] +1
合并同类项
dp[i]=(sigma(j=1..k1+k2+k3)p[j]*A[j+i] +p[0])*dp[0]+ sigma(j=1..k1+k2+k3)p[j]*B[j+i]+1
A[i]=(sigma(j=1..k1+k2+k3)A[j+i]*p[j] +p[0]) B[i]=sigma(j=1..k1+k2+k3)B[j+i]*p[j]+1
这样我们就可以逆推A[i],B[i]
那么最后的答案就是B[0]/(1-A[0])
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 503
using namespace std;
int n,a,b,c,k1,k2,k3,T;
double A[N],B[N],p[N];
int main()
{
freopen("a.in","r",stdin);
scanf("%d",&T);
while (T--) {
scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c);
double p0=1.0/k1/k2/k3;
memset(p,0,sizeof(p));
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) p[i+j+k]+=p0;
memset(A,0,sizeof(A));
memset(B,0,sizeof(B));
for (int i=n;i>=0;i--) {
A[i]=p0; B[i]=1;
for (int j=1;j<=k1+k2+k3;j++) {
A[i]+=p[j]*A[i+j];
B[i]+=p[j]*B[i+j];
}
}
printf("%.16lf\n",B[0]/(1.0-A[0]));
}
}