poj 3744 Scout YYF 1 (概率DP+矩陣快速冪)

F - Scout YYF I
Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u
Submit Status

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

題意:

有一段路,路上有n個陷阱,每一次只能向前走一步或者兩步,求安全走過這段路的改路

 

分析:

設dp[i]表示安全走過第i個陷阱的概率

那麼dp[i+1]=dp[i]*(1-p(走到第i+1個陷阱))

因爲每次只能走一步或者兩步,所有安全走過第i個陷阱後的位置一定在a[i]+1;\

其中a[i]表示第i個陷阱的位置

求從a[i]+1,走到a[i+1]的概率的時候我們需要用到矩陣來經行優化

ans[i]表示走到位置i的概率

ans[i] = p*ans[i-1]+(1-p)*ans[i-2];

ans[0]=0,ans[1]=1;

都說G++比C++要好,但是本題最好用C++提交。

如果用G++提交,浮點型輸出一定要用%f,否則會WA。

這是因爲G++標準的浮點型輸出用%f,而不是%lf。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <math.h>
#include <string.h>
using namespace std;
const int maxn=15;
int cnt[maxn];
double dp[maxn];
double p;
int n;
struct matrix
{
    double data[2][2];
};
matrix I={1,0,0,1};
matrix multi(matrix a,matrix b)
{
    matrix c;
    memset(c.data,0,sizeof(c.data));
    for(int i=0;i<2;i++)
    for(int j=0;j<2;j++)
    for(int k=0;k<2;k++)
    c.data[i][j]+=a.data[i][k]*b.data[k][j];
    return c;
}
double pow(matrix a,int b)
{
    matrix ans=I;
    while(b)
    {
        if(b&1)
        {
            ans=multi(ans,a);
            b--; //減比不減更好 雖然都對 但是減了更好理解一點
        }
        b>>=1;
        a=multi(a,a);
    }
    return ans.data[0][0];
}
int main()
{
    while(cin>>n>>p)
    {
        memset(dp,0,sizeof(dp)); //該初始化的地方一定要初始化
        cnt[0]=0;  //爲第一個雷做準備的
        for(int i=1;i<=n;i++)
            cin>>cnt[i];
        sort(cnt,cnt+n+1);
        dp[0]=1.0; //不是0
        matrix a={p,1-p,1,0}; //初始化矩陣,注意這個的推導過程
        for(int i=1;i<=n;i++)
        //要1減去這個概率 因爲這個概率是踩上雷的
        dp[i]=dp[i-1]*(1-pow(a,cnt[i]-cnt[i-1]-1));  //注意不要丟括號
        //注意是乘法不是加法 把每段概率乘起來
        //注意是-1不是+1
        //從上一個雷的下一個起 要走cnt[i]-cnt[i-1]-1步 才能到達下一個雷
        //雷在1和5 從2走到5 需要3步 5-1-1=3
        printf("%.7f\n",dp[n]);
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章