问题描述
共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
输入格式
一行两个正整数n和m
输出格式
一个实数P表示答案,保留4位小数。
样例输入
2 3
样例输出
0.7500
数据规模和约定
1≤n,m≤20
---------------------------------------------------------------------------------------------------------------------------------
首先考虑简单情况,当m<n,即 买的印章个数<印章种类 时,集齐n种印章的概率为0;
当印章种类个数n为1时,无论买了几张印章(m>=1),集齐的概率都为1;
接下来使用动态规划的思想,以m=4,n=3为例,设置数组dp[3][4];
每种印章抽到的概率为P = ;(此处为 )
dp[0][0]表示用1张印章集齐1种印章的概率:种类可以为n(此处为3)种中的任意一种,每种抽到的概率为P,则dp[0][0]=n*P=1;
dp[1][0]表示用2张印章集齐1种印章的概率:第1张印章的种类为3种中的任意一种,第2张印章的种类与第1张印章的种类相同,dp[1][0]=n*p*p=P
dp[i][0]表示用i+1张印章集齐1种印章的概率:dp[i][0]=
dp[1][1]表示用2张印章集齐2种印章的概率:第1张印章的种类为n(此处为3)种的任意一种,第2张印章的种类为剩下n-1(此处为2)种印章的任意一种,则dp[1][1]=(n*P)*[(n-1)*P]=dp[0][0]*(n-1)*P
dp[2][2]表示用3张印章集齐3种印章的概率:第1张印章的种类为n(此处为3)种的任意一种,第2张印章的种类为剩下n-1(此处为2)种印章的任意一种,第3张印章的种类为n-2(此处为1)种的任意一种,则dp[2][2]=(n*P)*[(n-1)*P]*[(n-2)*P]=dp[1][1]*(n-2)*P
dp[i][j](i==j)表示用i+1张印章集齐i+1种印章的概率:第1张印章的种类为n种的任意一种,第2张印章的种类为剩下n-1种印章的任意一种,.....以此类推第i+1张印章的种类为n-i种的任意一种,则dp[i][j]=dp[i-1][j-1]*(n-i)*P
dp[2][1]表示用3张印章集齐2种印章的概率:分为两种情况,第一种情况为前2张印章已经集齐了2种印章,则第3张印章的种类可以为该2种的任意一种,该概率为dp[1][1]*2*P;第二种情况为前2张印章只集齐1种印章,则第3张印章的种类为剩下n-1(此处为2)种印章的任意一种,该概率为dp[1][0]*(n-1)*P;因此,dp[2][1]=dp[1][1]*2*P+dp[1][0]*(n-1)*P
dp[i][j](i!=j)表示用i+1张印章集齐j+1种印章的概率:第一种情况为前i张印章已经集齐j+1种印章,此时第i+1张印章的种类可以为该j+1种印章的任意一种,该情况下的概率为dp[i-1][j]*(j+1)*P;第二种情况为前i张印章仅集齐j种印章,则第i+1张印章的种类为剩下的n-j种的任意一种,该情况下的概率为dp[i-1][j-1]*(n-j)*P;因此,dp[i][j]=dp[i-1][j]*(j+1)*P+dp[i-1][j-1]*(n-j)*P
最终买m张印章,集齐n种印章的概率为dp[m-1][n-1]
张数/种数 | 1 | 2 | 3 |
1 | 1 | 0 | 0 |
2 | 1/3 | 2/3 | 0 |
3 | 1/9 | 2/9 | |
4 | 1/27 |
#include <iostream>
#include <cmath>
#include<iomanip>
using namespace std;
double dp[25][25], p;
int main()
{
int n,m;
cin>>n>>m;
p = 1.0 / n; //每种出现的概率
for ( int i = 0; i < m; i++ ) {
for ( int j = 0; j < n; j++ ) {
if ( i < j ) dp[i][j] = 0;
if(i==0&&j==0)
{
dp[i][j]=1;
}
else if ( i!=0&&j == 0 ) {
dp[i][j] = pow (p, i); //p^(i)
}
else if(i==j){
dp[i][j] = dp[i-1][j-1] * ((n-i)*p);
}
else
{
dp[i][j]=dp[i-1][j]*(j+1)*p+dp[i-1][j-1]*(n-j)*p;
}
}
}
cout<<fixed<<setprecision(4)<<dp[m-1][n-1];
return 0;
}