问题描述
问题描述
共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
输入格式
一行两个正整数n和m
输出格式
一个实数P表示答案,保留4位小数。
样例输入
2 3
样例输出
0.7500
数据规模和约定
1≤n,m≤20
解题思路
用动态规划的思想
1:状态表示:dp [ i ] [ j ]表示的是在买 i 张印章时小A集齐 j 种印章的概率.
2:状态转移方程 : dp[i][j] = (n - (j - 1)) * p * dp[i - 1][j - 1] + j * p * dp[i - 1][ j ]; ,现在可能读不懂下面有详细解释。
3,填表顺序:从从左到右,从上到下。
假设买 i 张印章时集齐了 j 种印章。
小A 买印章只有两种可能,一是与前面买的相同(与前面买的印章重复了),二是与前面的印章不同(与前面买的印章没有重复)。
在这的基础上分三种情况:a.当 i < j 时,也就是买的印章小于印章的种类,那肯定集齐的概率为 0 。
b.当 j==1,i <= m 时,也就是说买 i 张印章集齐一张印章,dp[1][1]=1表示买一张集齐一张的概率是 1,当 i >1 时,dp [ i ] [ j ]=(1/n) * (n-1) 。这样理解:假设我买了 3 张印章,这三张印章都是一样的,从第二张开始,第二张与第一张相同的概率是 1/3 ,第三张与第二张相同的概率也是 1/3,所以 dp[3][1]=(1/3) * (1/3) = (1/3) * ( 3-1) = (1/n) * (n-1) 。
c. 剩下的情况 i >= j , j > 1 时,也就是买的印章大于等于印章的种类且集齐的印章不为 1 ,如果 j 为 1 就是情况 b 。买第 i 张印章时有两种情况 第一种是买的印章没有重复, dp[ i ][ j ] = (n - (j - 1)) * p * dp[i - 1][j - 1],(n - (j - 1)表示没有买到的印章种数,用印章种数减去集齐的印章种数,p 就是每一种印章的概率 1/n ,dp[i - 1][j - 1] 表示上一次买印章集齐了 j -1 张,第二种情况是买到重复的印章, dp[ i ][ j ] = j * p * dp[i - 1] [ j ] , j 表示买到的印章种数,p 就是每一种印章的概率 1/n, dp[i - 1] [ j ]表示上一次买印章集齐了 j 张。
代码
#include<stdio.h>
#include<math.h>
int main()
{
int m, n;
scanf("%d%d", &n, &m);//2 3
float dp[21][21] = { 0.0 }, p = 1.0 / n;
int i = 1,j = 1;
dp[1][1] = 1;
for (i = 1; i <= m; i++)//m=3
{
for (j = 1; j <= n; j++)//n=2
{
if (i < j)
dp[i][j] = 0;
if (j == 1)
dp[i][j] = pow(p, i - 1);
else
{
dp[i][j] = (n - (j - 1)) * p * dp[i - 1][j - 1] + j * p * dp[i - 1][j];
}
}
}
printf("%.4f", dp[m][n]);
return 0;
}