poj 3744 Scout YYF I(概率DP&矩阵快速幂)

Scout YYF I
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 4045   Accepted: 1037

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

POJ Monthly Contest - 2009.08.23, Simon


题意:

  你在一条布满地雷的道路上,开始在坐标1。每次有概率P向前走一步,有概率1-P向前走两步。道中路某几个点上会有地雷,问你安全通过的概率。地雷数N<=10,坐标范围在100000000内。


思路:
假设dp[i]表示安全走到i点的概率,那么dp[i]=P*dp[i-1]+(1-P)*dp[i-2]。很简单的一个转移,但是坐标范围太大了。直接递推爆内存,而且肯定也会超时。

我们换一个思路,假设x[i]表示第i个地雷的坐标。对于任何两个地雷x[i-1]+1~~x[i]之间,只会有一个地雷,那就是x[i]。我们安全通过该段的概率等于1 -踩到x[i]的概率。为什么可以这样呢。

我们前x[i]-1个位置看成一个位置。下一个位置只有两种可能。1.走到x[i]。2.走到x[i]+1。所以安全出来的概率就为1-踩到x[i]的概率。
也就是说,我们将n个地雷分成n段分别处理。每次都可以得到一个安全通过某一段的概率,最后将这些概率乘起来就是答案了。
由于数据比较大。
于是我们用矩阵来优化一下。
我们为这个dp[i]=P*dp[i-1]+(1-P)*dp[i-2]构造一个矩阵
| P ,1-P |

| 1 , 0   |

那么dp[n]就是该矩阵N次方后的第v[0,0]个元素。
因为。

|dp[n]   |           |p      1-p|^n-1     |dp[1]|

                  =                           *

|dp[n-1]|          |1          0|            |dp[0]|

而dp[1]=p。dp[0]=1。所以相当于矩阵的N次方去v[0,0]。

通过快速幂,很快就可以求出答案了。

#include <iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;

class tra//矩阵结构
{
public:
    int row,col;//行列
    double v[3][3];
    tra operator*(tra &tt)//矩阵相乘。前面矩阵的列必须和后面矩阵的行相同
    {
        int i,j,k;
        tra temp;
        temp.row=row;
        temp.col=tt.col;
        for(i=0; i<row; i++)
            for(j=0; j<tt.col; j++)
            {
                temp.v[i][j]=0;
                for(k=0; k<col; k++)
                    temp.v[i][j]+=v[i][k]*tt.v[k][j];
            }
        return temp;
    }
};
int pos[15];
tra pow_mod(tra x,int i)//矩阵快速幂
{
    tra base=x,ans;
    ans.row=ans.col=2;//ans初始化为
    ans.v[0][0]=ans.v[1][1]=1;  //|1  0|
    ans.v[0][1]=ans.v[1][0]=0;  //|0  1|相当于实数里的1
    while(i)
    {
        if(i&1)
            ans=ans*base;
        base=base*base;
        i>>=1;
    }
    return ans;
}
int main()
{
    tra x,t;
    int i,n;
    double p,ans;
    pos[0]=0;

    while(~scanf("%d%lf",&n,&p))
    {
        for(i=1;i<=n;i++)
            scanf("%d",pos+i);
        sort(pos+1,pos+n+1);
        if(pos[1]==1)
        {
            printf("%.7lf\n",0.0);
            continue;
        }
        x.row=x.col=2;
        x.v[0][0]=p;
        x.v[0][1]=1-p;
        x.v[1][0]=1;
        x.v[1][1]=0;
        ans=1;
        for(i=1;i<=n;i++)
        {
            if(pos[i]-pos[i-1]==0)
                continue;
            t=pow_mod(x,pos[i]-pos[i-1]-1);
            ans*=(1-t.v[0][0]);
        }
        printf("%.7lf\n",ans);
    }
    return 0;
}



你可能感兴趣的:(c,算法,ACM)