[题解] 概率$DP$
[题解] 概率\(DP\)
原题链
解题思路
这是第一道自己做出来的概率\(dp\)题
这个题其实有两种做法。
第一种:设期望
设\(f[i][j]\)表示当前考虑第\(i\)个人,在\(j\)时刻电梯里的期望人数,那么很容易得到转移方程:要么是进来一个人,要么是没进来人,所以\(f[i][j]=(f[i-1][j - 1]+1)*p+f[i][j-1]*(1-p)\)
第二种:设概率
设\(f[i][j]\)表示 \(i\)时刻电梯里有\(j\)个人的概率。同样很轻松的得到转移方程:\(f[i][j]=f[i - 1][j]*(1-p)+f[i -1][j-1]*p\),不过要注意的是如果已经有\(n\)个人了的话,就不能再用之前的转移方程了。因为如果上一个时刻电梯已经有\(n\)个人的话现在一定还是\(n\)个人,不用乘概率。也就是说\(f[i][n] = f[i-1][n]+f[i-1][n-1]*p\)。如果一开始电梯上还没有人,那么从\(f[i-1][j-1]\)转移过来是不合法的,因为不存在\(-1\)个人。
这两种做法唯一的区别就是转移方程中对于电梯进来人这个状态的描述,如果是算期望我们知道期望等于权值乘以概率,所以如果电梯进来人的话要表示成\((f[i-1][j-1]+1)*p\),而如果是设概率的话则不用考虑人数(权值)的变化。当然两个的答案统计方法也不一样。如果是期望的话直接输出就好了。如果是概率的话依然考虑期望的定义,需要枚举最终的时刻电梯内不同人数的概率,答案就是\(\sum_{i=1}^nf[T][i]*i\)
代码
#include <bits/stdc++.h>
using namespace std;
double f[2010][2010];
int main(){
int n,T;
double p;
scanf("%d%lf%d",&n,&p,&T);
for(int i = 1;i <= n;i++){
for(int j = 1;j <= T;j++){//设期望
f[i][j] = (f[i - 1][j - 1] + 1) * p + f[i][j - 1] * (1 - p);
}
}
printf("%.7lf",f[n][T]);
return 0;
}
#include <bits/stdc++.h>
using namespace std;
double f[2010][2010];
int main(){
int n,T;
double p;
scanf("%d%lf%d",&n,&p,&T);
f[0][0] = 1.000;
for(int i = 1;i <= T;i++){//设概率
for(int j = 0;j <= n;j++){
if(j == n)//特殊情况,只能从n或n-1转移
f[i][j] = f[i - 1][j] + f[i - 1][j - 1] * p;
else if(j == 0)//特殊情况,只能从f[i-1][0]转移
f[i][j] = f[i - 1][j] * (1 - p);
else f[i][j] = f[i - 1][j] * (1 - p) + f[i - 1][j - 1] * p;
}
}
double ans = 0.0;
for(int i = 0;i <= n;i++)ans += f[T][i] * i;//有概率推算期望
printf("%.7lf",ans);
return 0;
}