zoukankan      html  css  js  c++  java
  • 【POJ3744】Scout YYF I-概率DP+矩阵加速优化

    题目大意:一个侦察兵要通过一条“地雷之路”,他从第一个位置开始,有p的概率向前走一步,有(1-p)的概率向前走两步,地雷之路上有n颗地雷,位置在[1,1000000000]之间,问侦察兵顺利通过地雷之路(即走过第n个地雷且不踩到任何地雷)的概率。

    做法:当i-1和i-2不是雷时,很容易得出递推方程:f[i]=f[i-1]*p+f[i-2]*(1-p),其中f[i]为安全走到第i个位置的概率。而安全通过第i颗雷的概率为f[coor[i]-1]*(i-p)(coor[i]为第i颗雷的坐标),而安全通过第i颗雷的概率就是安全走到第coor[i]+1个位置的概率,即f[coor[i]+1]=f[coor[i]-1]*(1-p),所以我们最终要求的就是f[coor[n]+1],而除了通过雷时需要特殊处理,其他的步骤都是相似的,因此可以将问题分成n段处理:1~coor[1],coor[1]+1~coor[2],......,coor[n-1]+1~coor[n]。由于数字很大,我们可以利用矩阵进行优化。设矩阵F[i]={f[i] f[i-1]},转移矩阵A={p 1-p 1 0},设两颗雷的坐标先后为s和t,可得:F[t-1]=A^(t-s-2)*F[s+1](想一想,为什么?),求出f[t-1],再计算f[t+1]=f[t-1]*(1-p),再进行下一个阶段的计算...最后算出f[coor[n]+1],即答案。注意要特判t-s=1的情况,防止进行快速幂时运行错误。而且,输入中地雷的坐标并不一定是按升序给出的,所以要先读完所有的坐标并排序过后才能进行处理(本人就被坑了......RE了一次......囧)。最后要注意的是,结果要精确到七位小数(听说网上很多大牛都被坑了,不解),不要弄错了。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,last,coor[11];
    double p,start;
    struct matrix
    {
      double s[3][3]; 
    }M[32],E;
    
    bool cmp(int a,int b)
    {
      return a<b;
    }
    
    void clear(matrix &A)
    {
      for(int i=1;i<=2;i++)
        for(int j=1;j<=2;j++)
    	  A.s[i][j]=0;
    }
    
    matrix mult(matrix A,matrix B)
    {
      matrix S;
      clear(S);
      for(int i=1;i<=2;i++)
        for(int j=1;j<=2;j++)
    	  for(int k=1;k<=2;k++)
    	    S.s[i][j]+=A.s[i][k]*B.s[k][j];
      return S;
    }
    
    matrix power(int x)
    {
      matrix S;
      S=E;
      int i=0;
      while(x!=0)
      {
        if (x&1) S=mult(S,M[i]);
    	i++;x>>=1;
      }
      return S;
    }
    
    int main()
    {
      clear(E);for(int i=1;i<=2;i++) E.s[i][i]=1;
      while(scanf("%d%lf",&n,&p)!=EOF)
      {
        for(int i=1;i<=n;i++) scanf("%d",&coor[i]);
    	sort(coor+1,coor+n+1,cmp);
        M[0].s[1][1]=p;M[0].s[1][2]=1-p;
    	M[0].s[2][1]=1;M[0].s[2][2]=0;
    	for(int i=1;i<=31;i++) M[i]=mult(M[i-1],M[i-1]);
    	bool flag=1;
    	coor[0]=0;start=1;
        for(int i=1;i<=n;i++)
    	{
    	  if (coor[i]-coor[i-1]==1) {printf("0.0000000
    ");flag=0;break;}
    	  else start=start*power(coor[i]-coor[i-1]-2).s[1][1]*(1-p);
    	}
    	if (flag) printf("%.7lf
    ",start);
      }
      
      return 0;
    }
    


  • 相关阅读:
    spring和mybatis的结合
    SpringMVC
    springdata
    springboot的总结
    SpringAop代理模式笔记
    springcloud
    完全二叉树和满二叉树
    C# 读取EXCEL文件的三种经典方法
    C#加密app.config中连接字符串的代码
    c#winform 程序 App.config文件加密(SDK命令)
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793916.html
Copyright © 2011-2022 走看看