士兵從起點1出發,每次移動有p的概率走一步, 有1-p的概率走兩步,已知有n個格仔有地雷,問士兵不踩地雷的概率。
第一道真正意義上的概率dp題目,一開始打算令dp[i]意為更新到i點時踩雷的概率,dp[i]=p*dp[i-1]+(1-p)*dp[i-2],這樣寫看上去也是對的(第一眼看上去的角度上來說),但是其實並不符合題意,只能在很小的意義上保持正確性。關於錯誤原因,我是這樣理解的:踩雷這個事件本身是沒辦法連續的,因為人不可能在i-1點踩過雷之後再跑去i點踩雷(假設i-1點和i點都有雷),而這個現實意義上的不可能連續導致我們實際上以合理的角度理解這種更新方式,可能從純粹數學的角度來說可以以某種方式將其轉化為正確的更新方程,但是也已經超出了我的能力之外。
轉換思維,考慮人走到i點的概率dp[i],dp[i]=p*dp[i-1]+(1-p)*dp[i-2]。於是將n個地雷分開處理,乙個地雷不踩走到終點的概率a是我們要求的,其對立面也就是踩到任意乙個地雷的概率,設踩到地雷1的概率為b1,踩到地雷2的概率為b2,最終踩到任意乙個地雷的概率也就是b1*b2*b3…*bn,最終答案也就是1-b1*b2*b3…*bn。
設地雷1位置為a[1],地雷2位置為a[2]。這個b1,b2也就等於人走到a[1]點的概率dp[a[1]]。
但要注意一點:因為是把n個地雷分開對待,所以走過乙個地雷都認為是乙個新的起點,將到達地雷下乙個格仔的dp[a[i]+1]應視為1。
中間的轉移部分用矩陣快速冪加速,關於矩陣快速冪的構造,尤其是轉移矩陣與初始化矩陣,還不太清晰,等再做幾道題再總結。
#include
#include
#include
#include
using
namespace
std;
typedef
long
long ll;
int a[11];
int n;
double p;
struct mat
;mat mat_mul(mat x,mat y)}}
// printf("%f\n",res.a[0][0]);
return res;
}mat mat_pow(int n)
return res;
}int main()
sort(a+1,a+1+n);
double ans=1;
mat tem=mat_pow(a[1]-1);
// printf("%f\n",tem.a[0][0]);
ans*=(1-tem.a[0][0]);
for(int i=2;i<=n;i++)
mat tem=mat_pow(a[i]-a[i-1]-1);
ans*=(1-tem.a[0][0]);
}printf("%.7f\n",ans);
}return
0;}
poj3744 概率dp 矩陣乘法
在一條路上有n個地雷,有個sb人按照心情走在這條路上,往前走1步的概率是p,往前走2步的概率是 1 p 求他活著走過這條路的概率。很容易想到一種dp方程 f i p f i 1 1 p f i 2 然而一看範圍 1,100000000 怎麼可能不超時呢 然後可以這麼想 只要避開了最後乙個地雷不就安全...
poj 3744 概率dp 矩陣快速冪
poj 3744 題目大概是 小明要走一段路 有p的概率走一步 1 p 的概率走兩步 然後上面有雷 問安全通過的概率 題目通過雷把路程分為多段 把每段安全通過的概率相乘 就是整段安全通過的概率 設dp i 是小明安全到i的概率 到i的方式有兩種 一種是從 i 1 走一步 第二種是從 i 2 走兩步 ...
poj 3744 矩陣優化的概率DP
題意 你在一條布滿地雷的道路上,開始在座標1。每次有概率p向前走一步,有概率1 p向前走兩步。道中路某幾個點上會有地雷,問你安全通過的概率。地雷數n 10,座標範圍在100000000內。假設dp i 表示安全走到i點的概率,那麼dp i p dp i 1 1 p dp i 2 很簡單的乙個轉移,可...