题目大意
有 n ( n ≤ 20 ) n(n \le20) n(n≤20)个人去买东西,给出他们每个人买东西的概率 p i p_i pi,已知有 r r r个人买了东西,求每个人买东西的概率是多少。
解题思路
思路来源于:这位dalao ,他的这题题解
前置芝士:已知当事件
B
B
B发生时事件
A
A
A发生的概率如下图公式所示
在这题中,事件
B
B
B为有
r
r
r个人买了东西,事件
A
A
A为第
i
i
i个人买了东西。由此可以得知最后这个人买东西的概率为:
有
r
个
人
买
东
西
且
当
前
这
个
人
买
了
东
西
时
的
概
率
共
有
r
个
人
买
东
西
的
概
率
\frac{有r个人买东西且当前这个人买了东西时的概率}{共有r个人买东西的概率}
共有r个人买东西的概率有r个人买东西且当前这个人买了东西时的概率
因此我们可以用dp,先搜出
n
n
n个人中
r
r
r个人购物的概率,再依次求出有
r
r
r个人购物且第
i
i
i个人买东西时的概率,再套入公式,即可求出每个人购物的概率。
令
f
i
,
j
f_{i,j}
fi,j为前
i
i
i个人中有
j
j
j个人买东西,由此可推出状态转移方程:
f
i
,
j
=
{
f
i
−
1
,
j
第
i
个人是一定要买东西的那个人
f
i
−
1
,
j
∗
(
1
−
p
i
)
+
p
i
∗
f
i
−
1
,
j
−
1
这个人不一定买东西
f_{i,j}= \begin{cases} f_{i-1,j} & \text{第$i$个人是一定要买东西的那个人}\\ f_{i-1,j}*(1-p_i)+p_i*f_{i-1,j-1} & \text{这个人不一定买东西}\\ \end{cases}
fi,j={fi−1,jfi−1,j∗(1−pi)+pi∗fi−1,j−1第i个人是一定要买东西的那个人这个人不一定买东西
这个人不一定买东西时,有两种可能,第一种为这个人不购物,所以
f
i
,
j
=
f
i
−
1
,
j
∗
(
1
−
p
i
)
f_{i,j}=f_{i-1,j}*(1-p_i)
fi,j=fi−1,j∗(1−pi)(因为前
i
−
1
i-1
i−1个人中已经有
j
j
j个人购物了,所以乘上这个人不购物的概率
(
1
−
p
i
)
(1-p_i)
(1−pi));第二种为这个人购物,所以
f
i
,
j
=
f
i
−
1
,
j
−
1
∗
p
i
f_{i,j}=f_{i-1,j-1}*p_i
fi,j=fi−1,j−1∗pi(因为前
i
−
1
i-1
i−1人中只有
j
−
1
j-1
j−1人购物,所以这个人只有购物才能满足有
j
j
j个人买东西,所以乘上这个人购物的概率)。
代码
#include<bits/stdc++.h>
using namespace std;
int n,r;
double p[25],f[105][105];
double work(int x)//第x个人肯定购物
{
f[0][0]=1;//初始化
for(int i=1;i<=n;i++)
{
if(i==x)//如果这个人肯定购物
{
for(int j=0;j<=min(r,i);j++) f[i][j]=f[i-1][j];//由于肯定购物所以概率不变
continue;
}
for(int j=0;j<=min(i,r);j++)//因为不能出现购物的人比当前的人多
{
f[i][j]=(1-p[i])*f[i-1][j];//第一种可能(见解题思路)
if(j!=0) f[i][j]+=p[i]*f[i-1][j-1];//第二种可能(见解题思路)j!=0是因为j为0时数组访问到j-1会re
}
}
if(x==0) return f[n][r];//当没有锁定一个人肯定购物时每个人购物的概率(n个人中r个人购物的概率)
else return f[n][r-1];//因为这个人肯定购物,占了一个名额,所以要减去ta
}
int main()
{
cin>>n>>r;
for(int i=1;i<=n;i++)
{
cin>>p[i];
p[i]/=100;
}
double k=work(0);//求出n个人中r个人购物的概率
for(int i=1;i<=n;i++)
{
printf("%.6lf ",work(i)*p[i]/k);//work(i)*p[i]->肯定购物的那个人乘上ta购物的概率,套上公式
}
return 0;
}