zoukankan      html  css  js  c++  java
  • POJ 3744 Scout YYF I 概率DP+矩阵快速幂 好题

    Scout YYF I
    Time Limit: 1000MS   Memory Limit: 65536K
    Total Submissions: 5731   Accepted: 1617

    Description

    YYF is a couragous scout. Now he is on a dangerous mission which is to penetrate into the enemy's base. After overcoming a series difficulties, YYF is now at the start of enemy's famous "mine road". This is a very long road, on which there are numbers of mines. At first, YYF is at step one. For each step after that, YYF will walk one step with a probability of p, or jump two step with a probality of 1-p. Here is the task, given the place of each mine, please calculate the probality that YYF can go through the "mine road" safely.

    Input

    The input contains many test cases ended with EOF.
    Each test case contains two lines.
    The First line of each test case is N (1 ≤ N ≤ 10) and p (0.25 ≤ p ≤ 0.75) seperated by a single blank, standing for the number of mines and the probability to walk one step.
    The Second line of each test case is N integer standing for the place of N mines. Each integer is in the range of [1, 100000000].

    Output

    For each test case, output the probabilty in a single line with the precision to 7 digits after the decimal point.

    Sample Input

    1 0.5
    2
    2 0.5
    2 4

    Sample Output

    0.5000000
    0.2500000

    Source

     
     
     
     
    题意:一个特工在一条很远很远的布有地雷的路上走,这条路分成一个一个格子,编号从1开始
       然后特工走的时候,每次从i,会有p的概率走到i+1,会有1-p的概率走到i+2
       然后这条路上有n个地雷,n个地雷分别埋在这条路上的n个格子中,走到这些格子,当然就会boomboomboom
     
       给出n p
       然后是n个位置的编号
     
    注意数据范围
     
    n<=10,但是位置的编号是1<=编号<=100000000
     
    开始时,概率DP
    设dp[i]为从1走到i的概率
    则:dp[i]=p*dp[i-1]+(1-p)*dp[i-2]
     
    然而,这样要开100000000的数组,行不通
     
    看这条递推式,想到什么?没错,就是矩阵的快速幂
     
    这样还是要开啊
     
    换个思路:
    stp表示我现在的位置的编号
    now表示我走到了这里的概率
    pre表示我上一步的概率
    则初始时:pre=1.0
            now=pre*p;
            stp=2  
    设dp[i]表示走到第i个地雷时的概率,即走到pos[i]时的概率
    ,这样通过矩阵快速幂就可以求出走到pos[i]和pos[i]-1这2个位置的概率
    然后dp[i]=0,所以要继续走,必须从pos[i]-1这个时候走2步到达pos[i]+1的位置时的概率了
    然后更新stp,now,pre
    pre=pos[i]+1时的概率
    now=pre*p
    stp=pos[i]+2
     
    直到跨过了n个地雷
     
    因为题目是要求成功走出通道的概率
    只要特工跨过了这n个地雷后,就没有其他危险了,就一定可以走出通道了。
     
    所以输出的是成功到达pos[n]+1的概率
     
     
    犯了一个错误:n=n>>1被我写成了n==n>>1
    导致无限循环,然后交上去tle了,我还以为是姿势不对。
     
    这个程序0ms
     
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 
     5 using namespace std;
     6 
     7 #define LL long long
     8 
     9 struct Mat
    10 {
    11     double m[2][2];
    12 };
    13 Mat base;
    14 
    15 LL pos[15];
    16 
    17 Mat matmul(Mat a,Mat b)
    18 {
    19     Mat ret;
    20     for(int i=0;i<2;i++)
    21     {
    22         for(int j=0;j<2;j++)
    23         {
    24             ret.m[i][j]=0.0;
    25             for(int k=0;k<2;k++)
    26             {
    27                 ret.m[i][j]+=(a.m[i][k]*b.m[k][j]);
    28             }
    29         }
    30     }
    31     return ret;
    32 }
    33 
    34 Mat matPow(Mat a,LL n)
    35 {
    36     Mat b;
    37     b.m[0][0]=1;
    38     b.m[0][1]=0;
    39     b.m[1][0]=0;
    40     b.m[1][1]=1;
    41     while(n>0)
    42     {
    43         if(n&1)
    44             b=matmul(b,a);
    45         //刚开始这里写成了n==n>>1
    46         //所以无限循环
    47         //所以程序tle了
    48         //还以为是我这个姿势不对
    49         n=n>>1;
    50         a=matmul(a,a);
    51         //printf("%d
    ",n);
    52     }
    53     return b;
    54 }
    55 
    56 int main()
    57 {
    58     int n;
    59     while(scanf("%d",&n)!=EOF)
    60     {
    61         double p;
    62         scanf("%lf",&p);
    63         for(int i=1;i<=n;i++)
    64             scanf("%lld",&pos[i]);
    65         sort(pos+1,pos+n+1);
    66 
    67         base.m[0][0]=p;
    68         base.m[0][1]=1.0-p;
    69         base.m[1][0]=1.0;
    70         base.m[1][1]=0.0;
    71 
    72         double pre=1.0;
    73         double now=p;
    74         LL stp=2;
    75         for(int j=1;j<=n;j++)
    76         {
    77             Mat tmp=base;
    78             if(pos[j]-stp<0)
    79             {
    80                 pre=0.0;
    81                 break;
    82             }
    83 
    84             tmp=matPow(tmp,pos[j]-stp);
    85 
    86             double dp=tmp.m[1][0]*now+tmp.m[1][1]*pre;
    87             pre=dp*(1.0-p);
    88             now=pre*p;
    89             stp=pos[j]+2;
    90         }
    91         printf("%.7f
    ",pre);
    92     }
    93     return 0;
    94 }
    View Code
     
     
     
     
     
     
     
     
     
     
     
     
       
     
     
  • 相关阅读:
    JDBC 实例--JDBC通过工具类DBUtil连接到数据库,让我们不再恐惧操作数据库
    揭开JDBC的神秘面纱,让JDBC数据库的连接参数不再神秘
    实验六 最小代价生成树
    实验五 背包问题和带时限的作业排序
    实验四 图的遍历算法设计与实现
    实验三 跳表算法设计与实现
    实验二 伸展树算法设计与实现
    算法实例一 算法问题求解基础--欧几里得递归算法和递归算法
    2013年 蓝桥杯预赛 java 本科A 题目
    java常用开发工具类之 图片水印,文字水印,缩放,补白工具类
  • 原文地址:https://www.cnblogs.com/-maybe/p/4523346.html
Copyright © 2011-2022 走看看