[POJ3744]Scout YYF I 期望DP

来源:互联网 发布:哈尔滨黑夜骑士网络 编辑:程序博客网 时间:2024/04/30 07:30

说在前面

话说咱们一个初三的神犇的名字也是YYF(笑)
贴一份他的题解吧=w=yyf0309
这个题,是me第一次写矩阵快速幂,感觉写起来…..其实和普通快速幂几乎是一样的,只不过原来是数字相乘,现在是矩阵相乘而已。
而且还拿了个1A,开心!


题面

(某个)YYF在数轴上的1号点,他有p的概率向右跳一格,1-p的概率向右跳两格。数轴上分布有N个地雷,当(某个)YYF踩到地雷的时候,他就死了。问(某个)YYF安全的走过雷区的概率是多少

输入

多组数据,EOF结束
每组数据包含两行,第一行两个数字:整数N(≤10)和实数p(范围[0.25,0.75] )
第二行N个数,表示雷的位置(范围[1,100000000])

输出

每组数据输出一行一个实数,表示答案。保留七位小数。


题解

如果YYF遇到了一个地雷,并且还要能安全通过,那么只能是从地雷的前一格跳两步到地雷的后一格。
那么我们把整个数轴依据地雷所在位置划分成若干区域,如果YYF成功的越过了第i个雷,那么他下一步一定站在pos[i]+1上,到下一个雷被炸的概率就是从pos[i]+1跳到pos[i+1]的概率,用1减去这个概率得到的就是他安全通过的概率。

于是定义f[i]表示,到i位置YYF还活着的概率,明显有f[i] = p * f[i-1] + (1-p) * f[i-2]。
特别的,雷所在的位置的f值都为0【显然】


看似结束了的样子,然而数据规模特别大(1e8),还有多组数据,以至于我们直接递推会TLE。那么我们肯定需要对上述方法进行优化

解法一:矩阵快速幂
我们发现,这个递推式是形如f[i] = A * f[i-1] + B * f[i-2] + C * f[i-3] ….. 的形式,对于这类递推,我们都可以用矩阵乘法进行优化,如下所示:

[p11p0][ f[i1]  f[i2] ]=[ pf[i1]+(1p)f[i2] 1f[i1]]=[ f[i]  f[i1] ]

(这LaTex写的我心累= =)
好,我们发现,每计算一次,就相当于是乘上了一个矩阵
[p11p0]
那么对于每一小段之内的转移,我们就可以靠矩阵快速幂来辅助快速转移。
矩阵快速幂我就不讲了,原理和普通快速幂是一样的

解法二:dp收束
在liu_runda的博客园里,me见到了一种很新奇的解法。
就是说,因为每次我们转移都是f[i] = p * f[i-1] + (1-p) * f[i-2],并且p是固定的,因此这个dp存在收束性。可能转移了很多次之后,f会无限的逼近某一个值,我们只需要让这个”逼近”的误差在题目承受范围内就可以了。
liu_runda取的转移上限是500项,也就是说,大于如果一个雷离某个格子已经大于了500格,那么这个雷对那些格子的概率影响可以忽略不计,因此直接把远处的雷缩过来就好了
贴一个他的题解:liu_runda的POJ3744题解


下面是自带大常数的代码

#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;int N , pos[15] ;double p , tg[2][2] , tp[2] ;double M_pow( int b ){    double gm[2][2] = { { p , 1-p },                        { 1 , 0   } } ;    double s[2] = { 1 , 0 } ;    while( b ){        if( b&1 ){            tp[0] = gm[0][0] * s[0] + gm[0][1] * s[1] ;            tp[1] = gm[1][0] * s[0] + gm[1][1] * s[1] ;            s[0] = tp[0] ; s[1] = tp[1] ;        }        for( int i = 0 ; i <= 1 ; i ++ )            for( int j = 0 ; j <= 1 ; j ++ )                for( int k = 0 ; k <= 1 ; k ++ )                    tg[i][j] += gm[i][k] * gm[k][j] ;        for( int i = 0 ; i <= 1 ; i ++ )            for( int j = 0 ; j <= 1 ; j ++ )                gm[i][j] = tg[i][j] , tg[i][j] = 0 ;        b >>= 1 ;    }    return s[0] ;}int main(){    while( scanf( "%d%lf" , &N , &p ) != EOF ){        for( int i = 1 ; i <= N ; i ++ )            scanf( "%d" , &pos[i] ) ;        sort( pos , pos + N + 1 ) ;        double ans = 1 ;        for( int i = 1 ; i <= N ; i ++ )            ans *= ( 1 - M_pow( pos[i] - pos[i-1] - 1 ) ) ;        printf( "%.7f\n" , ans ) ;    }}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小孩做作业磨蹭怎么办 宝宝用左手写字怎么办 小孩动作太慢怎么办 幼儿园不去上学怎么办 嫌弃婆婆带孩子怎么办 孩子写字特别慢怎么办 幼儿园孩子不愿写字怎么办 孩子不愿用力写字怎么办 老公得了懒癌怎么办 太懒不想上班怎么办 写字太多手臂痛怎么办 小孩读书务工证怎么办 一年级孩子撕书怎么办 孩子上幼儿园不适应怎么办 一年级没办学籍怎么办 宝宝不爱做作业怎么办 儿子不爱做作业怎么办 我不想去上学怎么办 孩子写字爱玩怎么办 孩子不爱学习写字怎么办 孩子不爱学习成绩差怎么办 小孩默生字很差怎么办 孩子默写不出来怎么办 孩子不好好写字怎么办 大孩子书写差怎么办 孩子不愿意去学校怎么办 幼儿园不去了怎么办 小孩不喜欢吃菜怎么办 孩子不喜欢吃菜怎么办 13小孩不爱读书怎么办 孩子不爱学习的怎么办 小孩写磨磨唧唧怎么办 高考没发挥好怎么办 没房子孩子读书怎么办 孩子考试不检查怎么办 ps二维码不清晰怎么办 一年级小朋友不爱学习怎么办 宝宝突然不洗澡怎么办 做事老是怕出错怎么办 宝肚子有胀气怎么办 8岁儿童呕吐怎么办