概率dp(A - Scout YYF I POJ - 3744 )
题目链接:https://cn.vjudge.net/contest/276241#problem/A
题目大意:首先输入n和p,n代表地雷的个数,p代表走一步的概率,1-p代表走两步的概率,然后问你这个人安全走出雷区的概率
具体思路:我们可以很容易的推出递式,dp[i] = dp[i-1]*p+dp[i-1]*(1-p).但是这样线性过去的话,肯定会超时,所以我们可以借助矩阵加速,假设输入的地雷个数是n个,sto[1],sto[2],sto[3]...我们把1-sto[1]看成一段,sto[1]+1~sto[2]看成一段,这样一直循环下去就可以了,最终计算结果的时候,我们把每一段的概率相乘就可以了。相乘的时候注意,当前的a[1][1]这个矩阵代表的是正好走到这个雷点的概率,但是我们需要计算的是跳过这个雷点的概率,所以这一段的概率应该是(1-a[1][1])。每一段的第一个概率都是1,因为一定需要从这个点出发。
AC代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 using namespace std; 5 # define ll long long 6 const int maxn =10+10; 7 int sto[maxn]; 8 struct Matrix 9 { 10 double a[4][4]; 11 } tmp; 12 Matrix cal(Matrix t1,Matrix t2){ 13 Matrix t; 14 for(int i=1; i<=2; i++) 15 { 16 for(int j=1; j<=2; j++) 17 { 18 t.a[i][j]=0; 19 for(int k=1; k<=2; k++) 20 { 21 t.a[i][j]+=t1.a[i][k]*t2.a[k][j]; 22 } 23 } 24 } 25 return t; 26 } 27 Matrix quickpow(Matrix t,int ti) 28 { 29 Matrix tt; 30 if(ti==0)//如果有连着的两个雷,这个时候逃出去的概率是0,因为我们计算的时候是取第一个,然后这个时候ans就变成0了, 31 { 32 tt.a[1][1]=1; 33 } 34 else 35 { 36 tt=t; 37 ti--; 38 while(ti) 39 { 40 if(ti&1) 41 tt=cal(tt,t); 42 t=cal(t,t); 43 ti>>=1; 44 } 45 } 46 return tt; 47 } 48 int main() 49 { 50 int n; 51 double p; 52 while(~scanf("%d %lf",&n,&p)) 53 { 54 for(int i=1; i<=n; i++) 55 { 56 scanf("%d",&sto[i]); 57 } 58 sort(sto+1,sto+n+1); 59 double ans=1; 60 tmp.a[1][1]=p; 61 tmp.a[1][2]=1; 62 tmp.a[2][1]=1-p; 63 tmp.a[2][2]=0; 64 Matrix t; 65 t=quickpow(tmp,sto[1]-1); 66 ans=ans*(1-t.a[1][1]); 67 for(int i=2; i<=n; i++) 68 { 69 t=quickpow(tmp,sto[i]-(sto[i-1]+1)); 70 ans=ans*(1-t.a[1][1]); 71 } 72 printf("%.7lf\n",ans); 73 } 74 return 0; 75 }