zoukankan      html  css  js  c++  java
  • POJ 3744 Scout YYF I:概率dp

    题目链接:http://poj.org/problem?id=3744

    题意:

      有n个地雷,位置为pos[i]。

      在每个位置,你向前走一步的概率为p,向前走两步的概率为1-p。

      你的初始位置为1。

      问你通过雷区的概率。

     

    题解:

      表示状态:

        dp[i] = probability moving to i

        表示走到i的概率

     

      找出答案:

        ans = dp[last_mine+1]

        last_mine:最右边一颗雷的位置

     

      如何转移:

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

        if(i is a mine) dp[i] = 0

        对于位置i,有可能是从i-1走来的,也有可能是从i-2走来的。

        加法原理。

     

      边界条件:

        dp[1] = 1

        初始位置为1。

     

      优化:

        矩阵快速幂。

        对于某一段没有地雷的区间,是满足矩阵快速幂的(只用到递推式,dp不改为0)。

        所以分段进行矩阵快速幂。

        

        将雷区划分为n段:

        1~pos[1], pos[1]+1~pos[2], pos[2]+1~pos[3]...

        

        容斥原理:P(通过某一段雷区) = 1 - P(踩到最右边的雷)

        乘法原理:P(通过总雷区) = ∏ P(通过每一段雷区)

     

        矩阵格式:

        

        初始矩阵:

        

        特殊矩阵:

        

    AC Code:

      1 // state expression:
      2 // dp[i] = probability moving to i
      3 //
      4 // find the answer:
      5 // dp[last mine + 1]
      6 //
      7 // transferring:
      8 // dp[i] = dp[i-1] * p + dp[i-2] * (1-p)
      9 //
     10 // boundary:
     11 // dp[1] = 1
     12 // others = 0
     13 //
     14 // optimization:
     15 // quick pow for matrix
     16 // from x to y
     17 // res = start * special ^ (y-x)
     18 // dp[i] = res.val[0][0]
     19 #include <iostream>
     20 #include <stdio.h>
     21 #include <string.h>
     22 #include <algorithm>
     23 #define MAX_N 15
     24 #define MAX_L 5
     25 
     26 using namespace std;
     27 
     28 struct Mat
     29 {
     30     int n;
     31     int m;
     32     double val[MAX_L][MAX_L];
     33     Mat()
     34     {
     35         n=0;
     36         m=0;
     37         memset(val,0,sizeof(val));
     38     }
     39     void print_mat()
     40     {
     41         for(int i=0;i<n;i++)
     42         {
     43             for(int j=0;j<m;j++)
     44             {
     45                 cout<<val[i][j]<<" ";
     46             }
     47             cout<<endl;
     48         }
     49         cout<<endl;
     50     }
     51 };
     52 
     53 int n;
     54 int pos[MAX_N];
     55 double p;
     56 double ans;
     57 
     58 Mat make_unit(int k)
     59 {
     60     Mat mat;
     61     mat.n=k;
     62     mat.m=k;
     63     for(int i=0;i<k;i++)
     64     {
     65         mat.val[i][i]=1;
     66     }
     67     return mat;
     68 }
     69 
     70 Mat make_start()
     71 {
     72     Mat mat;
     73     mat.n=1;
     74     mat.m=2;
     75     mat.val[0][0]=0;
     76     mat.val[0][1]=1;
     77     return mat;
     78 }
     79 
     80 Mat make_special()
     81 {
     82     Mat mat;
     83     mat.n=2;
     84     mat.m=2;
     85     mat.val[0][0]=0;
     86     mat.val[0][1]=1-p;
     87     mat.val[1][0]=1;
     88     mat.val[1][1]=p;
     89     return mat;
     90 }
     91 
     92 Mat mul_mat(const Mat &a,const Mat &b)
     93 {
     94     Mat c;
     95     if(a.m!=b.n)
     96     {
     97         cout<<"Error: mul_mat"<<endl;
     98         return c;
     99     }
    100     c.n=a.n;
    101     c.m=b.m;
    102     for(int i=0;i<a.n;i++)
    103     {
    104         for(int j=0;j<b.m;j++)
    105         {
    106             for(int k=0;k<a.m;k++)
    107             {
    108                 c.val[i][j]+=a.val[i][k]*b.val[k][j];
    109             }
    110         }
    111     }
    112     return c;
    113 }
    114 
    115 Mat quick_pow_mat(Mat mat,long long k)
    116 {
    117     Mat ans;
    118     if(mat.n!=mat.m)
    119     {
    120         cout<<"Error: quick_pow_mat"<<endl;
    121         return ans;
    122     }
    123     ans=make_unit(mat.n);
    124     while(k)
    125     {
    126         if(k&1)
    127         {
    128             ans=mul_mat(ans,mat);
    129         }
    130         mat=mul_mat(mat,mat);
    131         k>>=1;
    132     }
    133     return ans;
    134 }
    135 
    136 void read()
    137 {
    138     pos[0]=0;
    139     for(int i=1;i<=n;i++)
    140     {
    141         cin>>pos[i];
    142     }
    143 }
    144 
    145 void solve()
    146 {
    147     sort(pos+1,pos+1+n);
    148     Mat special=make_special();
    149     ans=1;
    150     for(int i=1;i<=n;i++)
    151     {
    152         Mat start=make_start();
    153         Mat res=mul_mat(start,quick_pow_mat(special,pos[i]-pos[i-1]));
    154         ans*=(1-res.val[0][0]);
    155     }
    156 }
    157 
    158 void print()
    159 {
    160     printf("%.7f
    ",ans);
    161 }
    162 
    163 int main()
    164 {
    165     while(cin>>n>>p)
    166     {
    167         read();
    168         solve();
    169         print();
    170     }
    171 }
  • 相关阅读:
    十天冲刺开发第六天个人工作总结
    十天冲刺开发第五天个人工作总结
    人月神话阅读笔记1
    第六周进度条
    构建之法阅读笔记6
    连通数组的最大子数组和
    团队项目成员和题目
    第五周进度条
    四则运算———安卓版
    构建执法阅读笔记5
  • 原文地址:https://www.cnblogs.com/Leohh/p/7465622.html
Copyright © 2011-2022 走看看