【dp選講】淺談概率dp
【dp選講】概率與期望
說在前面
如果您此前還沒有了解過任何有關概率的內容的話,請先自行學習概率和期望的相關定理,然後再食用本部落格。
概率選題
注:概率和期望一般都是計算題,所以本部落格僅從解題的角度向您展示概率和期望,具體做題的時候還是有一點思考難度的,但是一般比較統一。
CF148D
題目大意:有兩個人往袋子裡面抓老鼠,老鼠分為兩類,一類是白老鼠,一類是黑老鼠,獲勝規則是誰先抓到白老鼠誰就獲勝。A抓老鼠的時候會附帶著有一隻老鼠溜出袋子,而B不會。如果最後是A抓到白老鼠或老鼠都跑光了,A也獲勝,請問B獲勝的概率是多少。輸入:N只白老鼠和M只黑老鼠。
分析:
設 $$dp[i][j]$$ 為袋子裡面有 i 只白老鼠和 j 只黑老鼠時的輪到B的獲勝概率。
初始化:$$dp[0][j]=0$$ ,$$dp[i][0]=1$$,意思分別是:如果一隻白老鼠都沒有的話,就必輸無疑;如果沒有黑老鼠,反而全是白老鼠的話,那就必勝無疑。
先考慮B在當前狀態下一次就抓到白老鼠的歐皇行為:
\[概率為:\frac{i}{i+j} \]接著思考B拿到黑老鼠,而A拿到白老鼠的非酋行為:
\[概率為:\frac{j}{i+j}*\frac{i}{i+j-1} \]【注:這是個分佈事件,第一步是B非酋拿黑擺爛,第二步才是A歐皇拿白。】
第三種:B抓到黑老鼠,A也抓到黑老鼠,最後又跑出一隻黑老鼠,此時的概率是:
\[\frac{j}{i+j}*\frac{j-1}{i+j-1}*\frac{j-2}{i+j-2} \]上面這種情況可以轉移到\(dp[i][j-3]\)
第四種:依舊是兩人抓到黑老鼠,但是跑出來的是白老鼠,此時的概率為:
\[\frac{j}{i+j}*\frac{j-1}{i+j-1}*\frac{i}{i+j-2} \]可轉移到\(dp[i-1][j-2]\).
根據以上式子,dp轉移即可。
#include<iostream> #include<cstdio> #define Maxn 5000 using namespace std; typedef double db; int n,m; db dp[Maxn][Maxn]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) dp[i][0]=1; for(int j=1;j<=m;j++) dp[0][j]=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { dp[i][j]+=(db)i/(i+j); if(j>=3) dp[i][j]+=(db)j/(i+j)*(j-1)/(i+j-1)*(j-2)/(i+j-2)*dp[i][j-3]; if(j>=2) dp[i][j]+=(db)j/(i+j)*(j-1)/(i+j-1)*i/(i+j-2)*dp[i-1][j-2]; } } printf("%.9lf",dp[n][m]); return 0; }
[Scout YYF I][http://poj.org/problem?id=3744]
題目大意:在一個數軸上,有n個雷。一開始,你在原點,現在,你有p的概率走一步,有(1-p)的概率走兩步,請問你有多大的概率可以安全通過雷陣?
分析:
直接算概率是不好求的,我們不如利用容斥原理,求出我們必定踩雷的概率(真非酋才能完成的壯舉),最後用1減去即可。
於是乎,我們可以逐步求解,求出我們踩第一個雷的概率,接著是第二個雷的概率,以此類推。
很自然地,我們列出轉移方程式:
\[dp[i]=p*dp[i-1]+(1-p)*dp[i-2] \]但是!這是一道多測題,單測都是極限的\(10^9\)了,線性遞推肯定不可行,我們考慮優化。
仔細思考——嗯,這道題是不是有點似曾相識?看起來有點像斐波那契的遞推式不是嗎?那麼這道題也許可以用矩陣乘法來優化。
於是,我們能列出這麼一個矩陣的遞推式:
\[p 1-p\\ 1 0 \]冪次方取得是每一段的長度。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Maxn 20000000
using namespace std;
typedef double db;
db p;
int n,pos[Maxn];
struct Matrix{
double mat[2][2];
void clear() {memset(mat,0,sizeof(mat));}
void idenaty() {clear();for(int i=0;i<2;i++)mat[i][i]=1;}
};
Matrix mul(Matrix a,Matrix b) {
Matrix res;
res.clear();
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
res.mat[i][j]=0;
for(int k=0;k<2;k++) {
res.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
}
}
}
return res;
}
Matrix power(Matrix x,int p) {
Matrix res;
res.idenaty();
Matrix base=x;
while(p) {
if(p&1) res=mul(res,base);
base=mul(base,base);
p>>=1;
}
return res;
}
int main() {
while(scanf("%d%lf",&n,&p)!=EOF) {
for(int i=1;i<=n;i++)
scanf("%d",&pos[i]);
db ans=1;
sort(pos+1,pos+n+1);
Matrix a;
a.clear();
a.mat[0][0]=p;a.mat[0][1]=1-p;
a.mat[1][0]=1;a.mat[1][1]=0;
Matrix ret;
ret.clear();
ret=power(a,pos[1]-1);
ans*=(1-ret.mat[0][0]);
for(int i=2;i<=n;i++) {
if(pos[i]==pos[i-1]) {continue;}
ret.clear();
ret=power(a,pos[i]-pos[i-1]-1);
ans*=(1-ret.mat[0][0]);
}
printf("%.7lf\n",ans);
}
return 0;
}