概率dp——hdu4089推公式+循环迭代
迭代是化简公式的常用技巧
dp[i][j]表示队伍中有i人,tomato排在第j位出现情况2的概率,那么先推出公式再进行简化
dp[i][1]=p21*dp[i][i] + p41
j<=k : dp[i][j]=p21*dp[i][j-1] + p31*dp[i-1][j-1] +p41
j>k : dp[i][j]=p21*dp[i][j-1] + p31*dp[i-1][j-1]
可见公式中的dp[i][1]和dp[i][i]是相关的,那么dp[i][j]也和dp[i][i]相关,所以只要迭代求出dp[i][i],然后再递推即可
在求dp[i][j]时所有dp[i-1][j]已经求出,所以后面的都是常数
因为dp[i][1]和dp[i][i]有关,所以需要迭代算方程先求出dp[i][i]
c数组是后面的常数,先处理出来即可
注意用滚动数组压缩内存,并特判
#include<bits/stdc++.h> using namespace std; const double esp = 1e-5; const int maxn = 2050; double c[maxn],pp[maxn],dp[2][maxn]; int main(){ double p1,p2,p3,p4; int n,m,k; while(scanf("%d%d%d%lf%lf%lf%lf",&n,&m,&k,&p1,&p2,&p3,&p4)!=EOF){ if(p4<esp){puts("0.00000");continue;} double p21=p2/(1-p1),p31=p3/(1-p1),p41=p4/(1-p1); pp[0]=1;c[1]=p41; for(int i=1;i<=n;i++)pp[i]=pp[i-1]*p21; dp[1][1]=p41/(1-p21); /* dp[i][1]=p21*dp[i][i] + p41 j<=k : dp[i][j]=p21*dp[i][j-1] + p31*dp[i-1][j-1] +p41 j>k : dp[i][j]=p21*dp[i][j-1] + p31*dp[i-1][j-1] 在求dp[i][j]时所有dp[i-1][j]已经求出,所以后面的都是常数 因为dp[i][1]和dp[i][i]有关,所以需要迭代算方程先求出dp[i][i] c数组是后面的常数,先处理出来即可 */ int cur=1; for(int i=2;i<=n;i++){ cur^=1; for(int j=2;j<=k;j++)c[j]=p31*dp[cur^1][j-1]+p41; for(int j=k+1;j<=i;j++)c[j]=p31*dp[cur^1][j-1]; double tmp=c[1]*pp[i-1];//通过迭代方程算出dp[i][i] for(int j=2;j<=i;j++)tmp+=c[j]*pp[i-j]; dp[cur][i]=tmp/(1-pp[i]); dp[cur][1]=p21*dp[cur][i]+c[1];//通过递推算出dp[i][1]及其余项 for(int j=2;j<i;j++)dp[cur][j]=p21*dp[cur][j-1]+c[j]; } printf("%.5f\n",dp[cur][m]); } }