概率dp(A - Scout YYF I POJ - 3744 )
阿新 • • 發佈:2019-01-13
題目連結: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,intti) 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 }