1. 程式人生 > >概率dp(A - Scout YYF I POJ - 3744 )

概率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 }