问题描述:
共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
输入格式:
一行两个正整数n和m
输出格式:
一个实数P表示答案,保留4位小数。
样例输入:
2 3
样例输出:
0.7500
数据规模和约定:
1≤n,m≤20
解题思路:
一共有m张印章,n种图案,每种图案的概率p=1/n;
现有i张印章,i张有j种图案,即dp[i][j]为i张印章共j种图案的概率(i张印章凑齐j种图案的概率)。
① 当 i < j 时,只有i张印章无法凑齐j种图案,即dp[i][j]=0;
② 当 j = 1 时,
当i = 1 时,满足i张印章j种图案(一张一种图案)dp [i] [j] = dp [1] [1] = 1;
当i > 1 时,如果满足 i 张印章j种图案( i 张一种图案),需要 i 张印章都一样,每个图案的概率都是dp [i] [1] = p^i;因为我们的图案不指定哪一种,所以我们的dp[i] [j]是n种图案的概率之和,就是p^i*n,因为p = 1/n;所以dp [i] [1] = p^(i-1) 。
③ 当 j > 1 时,
如果i-1张印章中,已经凑齐 j 种图案,第 i 张与前(i - 1)张中的一种图案相同,故满足条件;那么满足条件的第 i 张印章的概率为 j / n ,即dp[i][j] = dp [i-1] [j] *(j / n)=dp [i-1] [j] *j * p;
如果i-1张印章中,已经凑齐j-1种图案,第i张正好为第 j 种图案(与前j-1种不同),故满足条件;那么满足条件的第 i 张印章的概率为 (n - (j-1))/ n =(n-j+1)*p,即dp[i][j] = dp [i-1] [j-1] *(n-j+1)*p。
故此时满足 i 张印章j种图案的概率为上述两种情况之和,即dp[i] [j] = dp [i-1] [j] *j * p + dp [i-1] [j-1] *(n-j+1)*p 。
#include <bits/stdc++.h>
using namespace std;
double dp[30][30];
int main(){
memset(dp, 0, sizeof(dp));
int n,m;
cin>>n>>m;
double p = 1.0 / n;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
//不可能满足条件
if(i<j) dp[i][j]=0;
if(j==1){
//i张印章一种图案的概率
dp[i][j]=pow(p,i-1);
}
else {
//i张印章满足j种图案的概率
dp[i][j]=dp[i-1][j]*(j*p)+dp[i-1][j-1]*(n-j+1)*p;
}
}
}
//保留4位小数输出
cout.setf(ios::fixed);
cout<<fixed<<setprecision(4)<<dp[m][n]<<endl;
return 0;
}