POJ 3744 Scout YYF (矩陣優化的概率DP)
阿新 • • 發佈:2018-12-12
題目大意:
在一條不滿地雷的路上,你現在的起點在1處。在N個點處布有地雷,1<=N<=10。地雷點的座標範圍:[1,100000000].
每次前進p的概率前進一步,1-p的概率前進1-p步。問順利通過這條路的概率。就是不要走到有地雷的地方。
題目思路:
假設第i步的概率為pi
有這個矩陣冪公式可以將按照地雷的多少分成若干段,地雷與地雷之間可以用矩陣快速冪。
N個有地雷的點的座標為 x[1],x[2],x[3]```````x[N].
我們把道路分成N段:
1~x[1];
x[1]+1~x[2];
x[2]+1~x[3];
`
`
`
x[N-1]+1~x[N].
本題的WA可能就是,他可能在出發點1處也放有地雷,這時候要直接輸出0;
#include<algorithm> #include <cstdio> #include <cstring> #include <cmath> #include <iostream> using namespace std; #define N 6 int K,mod; struct Matrix { int r,c; double m[N][N]; Matrix(){} Matrix(int r,int c):r(r),c(c){} Matrix operator *(const Matrix& B)//乘法 { Matrix T(r,B.c); for(int i=1;i<=T.r;i++) { for(int j=1;j<=T.c;j++) { double tt = 0; for(int k=1;k<=c;k++) tt += m[i][k]*B.m[k][j]; T.m[i][j] = tt; } } return T; } Matrix Unit(int h) // 對角線矩陣 { Matrix T(h,h); memset(T.m,0,sizeof(T.m)); for(int i=1;i<=h;i++) T.m[i][i] = 1; return T; } Matrix Pows(int n) //矩陣冪 { Matrix P = *this,Res = Unit(r); while(n) { if(n&1) Res = Res*P; P = P*P; n >>= 1; } return Res; } void Print()//輸出 { for(int i=1;i<=r;i++) { for(int j=1;j<=c;j++) printf("%f ",m[i][j]); printf("\n"); } } }; int a[50]; int main() { int n; double p; while(scanf("%d%lf",&n,&p)!=EOF) { for(int i=0;i<n;i++)scanf("%d",&a[i]); sort(a,a+n); Matrix cnt(2,2),ans(2,1); int pos=2; if(a[0]==2) { ans.m[1][1]=0;ans.m[2][1]=1; } else { ans.m[1][1]=p,ans.m[2][1]=1; } cnt.m[1][1]=p,cnt.m[1][2]=1.0-p; cnt.m[2][1]=1,cnt.m[2][2]=0; for(int i=0;i<n;i++) { //ans.Print(); if(i>0&&a[i]==a[i-1])continue; if(a[i]<=2)continue; int num=a[i]-pos; pos=a[i]; ans=cnt.Pows(num)*ans; ans.m[1][1]=0; } if(a[n-1]==2) { printf("%.7f\n",1-p); continue; } else if(a[0]==1) { printf("%.7f\n",0); continue; } ans=cnt.Pows(1)*ans; printf("%.7f\n",ans.m[1][1]); } return 0; }