解题思路
动态规划,如下表所示,pp[i] [j]表示买 i 张凑齐 j 种印章的概率
题目中有 n 种印章, 每种概率是 1/n;
先来看i<j的时候:因为买 i 张最多只能凑齐 i 种,所以这种情况概率为0
再来看j=1的时候:
i=1:dp[i] [1]表示的意思是买 i 张凑齐 1 种的概率,很明显 i == 1 && j == 1 的时候dp[1] [1] = 1,因为你买一张是无论如何都可以凑齐一种的。
i > 1:i > 1 && j == 1. 意思就是买 i 张凑齐 1 种印章的概率,意味着买的这 i 张印章是同一种,概率就是 (1/n)^i,但是,我们这 i 张要么是第一种,要么是第二种…( 要么是第k种 ,1 <= k <= n )。最后还要乘上n,所以这个情况 dp[i] [j] = (1/n)^(i-1)
初始状态大致就上面这些了。
最后来看中间的状态 dp[i] [j]:
我们买的第 i 张,有两种状态,一:跟前面买的 i-1 张中有重复的 二:跟前面买的 i-1 张中没有重复的
比如:(总共有5种印章,标号1,2,3,4,5) 我正在买第5张,前面四张凑齐了1,2,3,4号,那么第5张如果也是1,2,3,4号中的一个就表示重复的;如果第5张是5号,就表示没有重复的。
一:有重复的:就表明前面买的 i-1 张,已经凑齐了 j 种。dp[i] [j] = dp[i-1] [j] * ( j / n );
二:无重复的
前面买的 i-1 张 凑齐了 j-1 种, 我们买的第 i 张与前面的不重复,就又凑齐了一种:dp[i] [j] = dp[i-1] [j-1] * (n-j+1) / n;
然后把两种情况加起来就是dp[i] [j] 的概率了。
代码
//共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
#include<stdio.h>
#include<math.h>
int n,m;
double pp(int i, int j)
{
if (!i || !j || i > j)
{
return 0;
}
else if (i == 1)
{
return pow(1.0 / n, j - 1);
}
else
{
return pp(i - 1, j - 1) * (n - i + 1) / n + pp(i, j - 1) * i / n;
}
return 0;
}
int main()
{
scanf("%d%d", &n, &m);
if (n == 1)
{
printf("1.0000");
}
else if (n > m)
{
printf("0.0000");
}
else
{
printf("%.4f", pp(n, m));
}
return 0;
}
参考文献