• poj3744 (概率DP+矩阵快速幂)


    http://poj.org/problem?id=3744

    题意:在一条铺满地雷的路上,你现在的起点在1处。在N个点处布有地雷,1<=N<=10。地雷点的坐标范围:[1,100000000].
    每次前进p的概率前进一步,1-p的概率前进2步。问顺利通过这条路的概率。就是不要走到有地雷的地方。
     
    分析:
    安全通过就是走到最右的地雷坐标+1 的位置(安全)
    有一道显然的转移方程 dp[i] = dp[i-1]*p + dp[i-2]*(1-p) ;   如果有地雷dp[i] 就为0,这样一直的递推下去可是我们发现地雷的坐标真的太大了,递推超时;然后我们在观察这个式子可以发现这是斐波那契数列,可以想到用矩阵快速幂解决 ,但是如果是出现了地雷,dp[i]就会改变,这样就无法使用快速幂。
    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].
     
    这样每一段只有一个地雷。我们只要求得通过每一段的概率。乘法原理相乘就是答案。
    对于每一段,通过该段的概率等于1-踩到该段终点的地雷的概率。
     
    就比如第一段 1~x[1].  通过该段其实就相当于是到达x[1]+1点。那么p[x[1]+1]=1-p[x[1]].
    但是这个前提是p[1]=1,即起点的概率等于1.对于后面的段我们也是一样的假设,这样就乘起来就是答案了。
     (可以理解为我走到那个位置炸了了,那安全的概率肯定是1-不满足的概率啊)
    对于每一段的概率的求法可以通过矩阵乘法快速求出来。
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    typedef long long ll;
    
    typedef vector<double>vec;
    typedef vector<vec >mat;
    int n;
    double p,T1,T2,pT1,pT2;
    mat mul(mat &A , mat &B)
    {
        mat C(A.size(),vec(B.size()));
    
        for(int i=0 ; i<A.size() ; i++)
        {
            for(int k=0 ; k<B.size() ; k++)
            {
                if(A[i][k]==0) continue;
                for(int j=0 ; j<B[0].size() ; j++)
                {
                    if(B[k][j]==0) continue;
                    C[i][j]=(C[i][j] + A[i][k]*B[k][j]);
                }
            }
        }
        return C;
    }
    mat qpow(mat A,ll n)
    {
        mat B(A.size(),vec(A.size()));
        for(int i=0 ; i<A.size() ; i++)
        B[i][i]=1;
        while(n>0)
        {
            if(n&1)
            B=mul(B,A);
            A=mul(A,A);
            n>>=1;
        }
        return B;
    }
    double so(int len)
    {
        mat A(2,vec(2));
        A[0][0]=p;A[0][1]=1-p;
        A[1][0]=1;A[1][1]=0;
        A = qpow(A,len-2);
        double T=A[0][0]*p+A[0][1];
        return T;
    }
    int x[11];
    bool vis[1000];
    double dp[10000];
    int main()
    {
        while(~scanf("%d%lf",&n,&p))
        {
            int Max=-1;
            for(int i=1 ; i<=n ; i++)
            scanf("%d",&x[i]),vis[x[i]]=1,Max=max(Max,x[i]);
            dp[1]=1;
            dp[2]=p;
            if(vis[1]) dp[1]=0;
            if(vis[2]) dp[2]=0;
            for(int i=3 ; i<=Max+1 ; i++)
            {
    
                dp[i]=dp[i-1]*p + dp[i-2]*(1-p);
                if(vis[i]) dp[i]=0;
            }
            printf("%0.7f
    ",dp[Max+1]);
    
        }
    }
    View Code
  • 相关阅读:
    SQL SERVER 2008 SA禁用,Windows帐户被删
    SQL Server表结构修改脚本
    请教高手,如何取得Target属性
    Installing Reporting Services on Windows 7, Vista or Windows Server 2008 无权限(rsAccessDenied)解决方法
    请教:如何在子页面关闭时把焦点设置到父页面的服务器控件上?
    order by newid() sql随机查询
    JS干货,笔记大全
    破解XP密码
    直接连接*.mdf 文件 获取随机数据
    总结C#获取当前路径的7种方法(转)
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/10940767.html
Copyright © 2020-2023  润新知