印章
问题描述
共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
输入格式
输出格式
样例输入
样例输出
数据规模和约定
解析:本题采用动态规划的方法
核心:从集合角度分析DP问题
1.状态表示 f(i,j) 因为有n m 两种状态
- 集合 买了i个印章 集了 j 种
- 属性 概率 (题目要求的就是概率)
2.状态计算,化整为零的过程
状态1 :j > i //不可能事件 集的种类比买的还多
状态2 :j == 1 //买了 i 个印章 只集了一种 也就是说都买了同一个
其余状态: f[i][j] 从下面两种情况变化而来
- f[i - 1][j - 1] ×再买一个印章为 (j-1) 种之外的概率
- f[i -1][j] x 再买一个印章为 j种 之内的概率
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 25;
int n, m;
double f[N][N]; //概率为小数
int main()
{
cin >> n >> m;
double p = 1.0 / n; //计算每种印章的概念
for(int i = 1; i <= m; i ++) //买 i个印章
for(int j = 1; j <= n; j ++) //集了 j种印章
{
if(j > i){
f[i][j] = 0; //不可能事件 集的种类比买的还多
}
if(j == 1){
//买了 i 个印章 集了一种
f[i][j] = pow(p, i - 1); //求p^(i-1)
}else{
//f[i][j] 从下面两种情况变化而来
//f[i - 1][j - 1] ×再买一个印章为 (j-1) 种之外的概率
// f[i -1][j] x 再买一个 为 j 之内的概率 ps: *p 等价于 /n
f[i][j] = f[i - 1][j - 1] *(n - j + 1) * p + f[i -1][j] *(j * p);
}
}
// 求的是买m个印章 集了n种的概率
printf("%.4lf",f[m][n]);
return 0;
}
本题:印章