原题我就不提供了, 大家可以自己上www.POJ.org搜索.
大概题意 :
小明要通过一条"地雷之路".路上有好多个地雷, 而小明现在站在路的开端(1号位置), 小明有P的概率向前移动一步, 有(1-P)的概率向前移动两步, 问小明能安全通过这条路的概率.
输入格式:
1 . 输入多组数据, 以EOF结束
2 . 每组数据包括两行, 第一行输入N,P , 分别表示地雷数目和走一步的概率;
第二行输入N个正整数, 表示地雷的位置;
输出格式:
每组数据的结果占据一行, 表示安全通过的概率, 以7位浮点数表示
示例输入:
1 0.5
2
2 0.5
2 4
示例输出:
0.5000000
0.2500000
解题思路 :
先将题目转化为概率DP(动态规划)的问题, 再优化为矩阵乘法问题.
1 . 使用最小优先队列来记录路上所有地雷的位置.
2 . 定义Dp[ i ]表示小明能安全到达第i号位置的概率.
3 . 状态转移方程 :
Dp[ i ] = P*Dp[i-1] + (1-P)Dp[i-2] ; // 第 i 号位置没有地雷
Dp[ i ] = 0; // 第 i 号位置有地雷
4 . 矩阵表达式:
5 . 当 i 号位置存在地雷时 , 设Dp[ i ] = 0;
6 . 当有两个连续位置存在地雷时, 最后结果必然为0
有了上述的理论基础, 我们可以给出如下代码:
#include <iostream>
#include <vector>
#include <queue>
#include <iomanip>
#include <functional>
using namespace std;
typedef unsigned int uint;
typedef uint SizeType;
typedef uint IndexType;
typedef double ValueType;
typedef vector<ValueType> RowType;
typedef vector<RowType> ContainerType;
// ...矩阵类的实现
class Matrix{
public:
Matrix( SizeType nRow, SizeType nCol, ValueType initVal )
:m_mtx( *(new ContainerType( nRow, RowType(nCol,initVal) )) ){}
Matrix( const Matrix& right ):m_mtx(*(new ContainerType( right.m_mtx ))){}
~Matrix(){ delete &m_mtx; }
inline SizeType GetRow()const{ return m_mtx.size(); }
inline SizeType GetCol()const{ return GetRow()?m_mtx[0].size():0;}
inline const ValueType& operator()( IndexType row, IndexType col )const{ return m_mtx[row][col]; }
inline ValueType& operator()( IndexType row, IndexType col ){ return m_mtx[row][col]; }
const Matrix& operator=( const Matrix& right ){ return (m_mtx = right.m_mtx,*this);}
const Matrix operator*( const Matrix& right )const{
Matrix Res( GetRow(), right.GetCol(), 0);
if( GetCol()==right.GetRow()){
const Matrix& left = *this;
SizeType row = GetRow(), col = right.GetCol(),end = GetCol();
for( IndexType i = 0; i < row; ++i)
for( IndexType j = 0; j < col; ++j)
for( IndexType t = 0; t < end; ++t )
Res(i,j) += left(i,t)*right(t,j);
}
return Res;
}// ...矩阵乘法
const Matrix& operator*=( const Matrix& right ){ return *this = *this*right; }
static Matrix GetIdentity( SizeType nDimension ){
Matrix Id( nDimension, nDimension, 0);
for( IndexType i = 0; i < nDimension; ++i ) Id(i,i) = 1;
return Id;
}// ...获得n阶单位矩阵
const Matrix operator^( uint N )const{
Matrix Res = GetIdentity( GetRow() ), Mul(*this);
while( N ){
if( N&1 ) Res *= Mul;
Mul *= Mul;
N>>=1;
}
return Res;
}// ...矩阵快速幂
const Matrix& operator^=( uint N ){ return *this = *this^N; }
protected:
ContainerType &m_mtx; //...矩阵容器
};
// ...数据集采用优先队列实现( 升序排序 )
typedef priority_queue< IndexType,vector<IndexType>,greater<IndexType> > DataSetType;
typedef queue< ValueType > ResultSetType; // ...结果集采用普通队列实现
void Calculate( DataSetType& DSet, ResultSetType& RSet,ValueType P){
Matrix Base(1,2,0); // ...基本概率矩阵: Base = [ dp(i), dp(i-1) ];
Matrix Ext(2,2,0); // ...线性组合描述矩阵 : dp(i+1) = dp(i)*P + dp(i-1)*(1-P) ;
uint N = 0,preN = 0,from = 1; // ...当前死亡位置, 前一个死亡位置, 开始位置
Ext(0,0) = P; // |- -|
Ext(0,1) = 1.0; // | P , 1 |
Ext(1,0) = 1-P; // Ext = | |
Ext(1,1) = 0; // | 1-P , 0 |
Base(0,0) = 1; // |- -|
while( !DSet.empty() ){
Matrix M(Ext);
preN = N; // ...记录前一次的死亡位置
N = DSet.top(); // ...获取下一个死亡位置
DSet.pop();
if( preN+1 == N ){ // ...如存在两个连续的死亡位置, 则必然无法成功渡过
RSet.push( 0.0 );
while( !DSet.empty() ) DSet.pop();
return;
}
M^=(N-from); // ...从上一个位置 到 下一个死亡位置, 需前进N-from步,即N-from次线性组合
Base*=M; // ...表示从起始位置Base,经过矩阵M描述的线性变换
Base(0,0) = 0.0;// ...那是一个死亡位置, 安全到达的概率必然为0
from = N;
}
RSet.push( Base(0,1)*Ext(1,0) );
}
int main(int argc, char** argv)
{
ResultSetType RSet; // ...结果集合
DataSetType DSet; // ...数据集合
uint N,data;
ValueType P;
while(cin >> N >> P){
for( uint i = 0; i < N; ++i) {
cin >> data;
DSet.push( data );
}
Calculate( DSet, RSet , P);
}
while( !RSet.empty() ){
cout << fixed << setprecision(7) << RSet.front() << endl;
RSet.pop();
}
return 0;
}