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
     
     
     
     
     
     
     
     
     
     
     
     
       
     
     
  • 相关阅读:
    【MOSS】SPUser的操作
    退出登录跳出框架页
    F12转到定义时,总是显示从元数据 转载粘贴
    简易代码生成器
    C语言I博客作业04
    第一周作业
    C语言I博客作业02
    C语言I博客作业02
    【DukeImage】Week_5 Segmentation
    【LeetCode】#7 Reverse Integer
  • 原文地址:https://www.cnblogs.com/-maybe/p/4523346.html
Copyright © 2011-2022 走看看