题目链接:http://poj.org/problem?id=3744
Description
Input
Output
Sample Input
1 0.5 2 2 0.5 2 4
Sample Output
0.5000000 0.2500000
题意:
一共有n个雷,分别在a[1] a[2] ……a[n] ;
每次走一步概率为 p ,走两步概率为 1 - p ,起始位置在1号位置;
求能安全通过所有雷的概率;
PS:
把整个过程划分成阶段处理:
1 ~ a[1]
a[1]+1 ~ a[2]
…………
a[n-1]+1 ~ a[n]
那么只要求出每次踩到雷的概率,再求反面,最后把所有阶段的结果连乘就好了。
ans[i]表示踩中i的概率,推出: ans[i] = p*ans[i-1] + (1-p)*ans[i-2]
构造矩阵:
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; struct Matrix { double m[5][5]; } I, A; double a[17]; //ans[i]表示猜到第i个地雷的概率 //ans[i] = p*ans[i-1] + (1-p)*ans[i-2]; const int ssize = 2; Matrix Mul(Matrix a,Matrix b) { int i, j, k; Matrix c; for(i = 1; i <= ssize; i++) { for(j = 1; j <= ssize; j++) { c.m[i][j]=0; for(k = 1; k <= ssize; k++) { c.m[i][j]+=(a.m[i][k]*b.m[k][j]); // c.m[i][j]%=mod; } } } return c; } Matrix quickpagow(int n) { Matrix m = A, b = I; while(n) { if(n & 1) b = Mul(b,m); n = n >> 1; m = Mul(m,m); } return b; } double solve(int l, int r) { if(l == r) return 1; if(r-l == 1) return 0;//相邻一定会踩到 Matrix tt = quickpagow(r-l-1); return 1 - tt.m[1][1];//反面 } int main() { int n; double p; while(~scanf("%d%lf",&n,&p)) { for(int i = 0; i < n; i++) { scanf("%lf",&a[i]); } sort(a,a+n); memset(A.m, 0,sizeof(A.m)); memset(I.m, 0,sizeof(I.m)); for(int i = 1; i <= ssize; i++) { I.m[i][i] = 1; } A.m[1][1] = p, A.m[1][2] = 1-p; A.m[2][1] = 1; double ans = solve(0,a[0]); for(int i = 1; i < n; i++) { ans *= solve(a[i-1],a[i]); } printf("%.7lf\n",ans); } }
POJ 3744 Scout YYF I(矩阵快速幂 概率dp)
原文地址:http://blog.csdn.net/u012860063/article/details/43532221