POJ 3744 Scout YYF I 概率DP+矩阵快速幂 好题

文章详细介绍了特工在一条布满地雷的长路上如何安全行走的算法,包括特工每次行动的概率计算和利用矩阵快速幂解决路径安全问题的方法。通过给出特工行走概率和地雷位置,读者可以学习到如何计算特工最终成功走出通道的概率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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",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\n",pre);
92     }
93     return 0;
94 }
View Code

 

 
 
 
 
 
 
 
 
 
 
 
 
   
 
 

转载于:https://www.cnblogs.com/-maybe/p/4523346.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值