1. 程式人生 > >POJ 3744 Scout YYF (矩陣優化的概率DP)

POJ 3744 Scout YYF (矩陣優化的概率DP)

題目大意:

在一條不滿地雷的路上,你現在的起點在1處。在N個點處布有地雷,1<=N<=10。地雷點的座標範圍:[1,100000000].

每次前進p的概率前進一步,1-p的概率前進1-p步。問順利通過這條路的概率。就是不要走到有地雷的地方。

題目思路:

假設第i步的概率為pi

\begin{pmatrix} pn\\ pn-1 \end{pmatrix}=\begin{pmatrix} p...1-p\\ 1.......0 \end{pmatrix}*\begin{pmatrix} pn-1\\ pn-2 \end{pmatrix}

有這個矩陣冪公式可以將按照地雷的多少分成若干段,地雷與地雷之間可以用矩陣快速冪。

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;
}