POJ-3744 Scout YYF I (矩阵优化概率DP)
题目大意:有n颗地雷分布在一条直线上,有个人的起始位置在1,他每次前进1步的概率为p,前进两步的概率为1-p,问他不碰到地雷的概率。
题目分析:定义状态dp(i)表示到了dp(i)的概率,则状态转移方程为dp(i)=p*dp(i-1)+(1-p)*dp(i-2)。要想安全通过x(i)到达x(i)+1只能由x(i)-1走两步,所以,可以将整条直线分成n段,那么从x(i-1)+1安全通过第 i 颗地雷概率为1-p(到达x(i))。坐标之间的距离又很大,所以可以用矩阵二分幂优化。
代码如下:
# include<iostream> # include<cstdio> # include<cstring> # include<algorithm> using namespace std; struct Matrix { int r,c; double m[2][2]; }; int x[12]; double p; Matrix multiply(Matrix a,Matrix b) { Matrix res; res.r=a.r; res.c=b.c; for(int i=0;i<res.r;++i){ for(int j=0;j<res.c;++j){ res.m[i][j]=0; for(int k=0;k<a.c;++k) res.m[i][j]+=a.m[i][k]*b.m[k][j]; } } return res; } Matrix myPow(Matrix a,int n) { if(n==0){ a.m[0][0]=a.m[1][1]=1; a.m[0][1]=a.m[1][0]=0; return a; }else{ Matrix res=myPow(a,n>>1); res=multiply(res,res); if(n&1) res=multiply(res,a); return res; } } double solve() { Matrix mat; mat.r=mat.c=2; mat.m[0][0]=p,mat.m[0][1]=1-p; mat.m[1][0]=1,mat.m[1][1]=0; sort(x+1,x+x[0]+1); Matrix temp=myPow(mat,x[1]-1); double ans=1-temp.m[0][0];///ans为安全通过第i颗地雷的概率。 for(int i=2;i<=x[0];++i){ if(x[i]==x[i-1]) continue; temp=myPow(mat,x[i]-x[i-1]-1); ans*=(1-temp.m[0][0]); } return ans; } int main() { while(~scanf("%d",&x[0])) { scanf("%lf",&p); for(int i=1;i<=x[0];++i) scanf("%d",x+i); printf("%.7lf\n",solve()); } return 0; }