问题描述
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
输入格式
一行两个正整数n和m
输出格式
一个实数P表示答案,保留4位小数。
样例输入
2 3
样例输出
0.7500
数据规模和约定
1≤n,m≤20
第一次想法
感觉是个概率问题,觉得可以简单解决
想法是n个盒子装m个球,通过先选n个球,分别放入n个盒子,其余的球随便放。
大概理解为n个抽到n种概率为(1/n)^n,那么m个就是还有一个Cmn
概率公式P=(1/n)^n*Cmn
只通过两个样例
代码如下:
#include<iostream>
#include<stdio.h>
#include<math.h>
using namespace std;
int main() {
int n, m;
double p;
int a[21];
a[0] = 1;
a[1] = 1;
for (int i = 2; i < 20; i++) {
a[i] = a[i - 1] * i;
}
cin >> n >> m;
if (n > m) {
p = 0;
printf("%.4lf", p);
return 0;
}
int t = m - n;
p = pow(1.0 / n, n) * a[m] / (a[t] * a[n]);
printf("%.4lf", p);
return 0;
}
这个代码是有问题的,应该是概率公式就是有问题的,算改路的时候加上了先后顺序,所以概率公式就是有问题的。概率公式推导太容易错了!!!!
转变想法,这个题可以用dp的思想来做
动态规划
首先共有n种印章
dp[i][j]为i个印章抽到j种印章的概率
分为两种情况
抽到一种新的印章
dp[i][j]=dp[i-1][j-1]*(n-j+1)/n
抽到重复印章
dp[i][j]=dp[i-1][j]j/n
那么总的概率为:
dp[i][j]=dp[i-1][j-1](n-j+1)/n+dp[i-1][j]*j/n
有一个值得注意的事情就是,当i<j的时候概率为0!
则代码如下:
#include<iostream>
#include<cmath>
#include<string.h>
using namespace std;
int main()
{
int n, m;
double dp[21][21];
memset(dp, 0, sizeof(dp));//头文件加#include<string.h>
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
if (i < j)
dp[i][j] = 0;
else if (j == 1)
dp[i][j] = pow(1.0 / n, i-1);
else
dp[i][j] = dp[i - 1][j - 1] * (n - j + 1) / n + dp[i - 1][j] * j / n;
}
}
printf("%.4lf", dp[m][n]);
return 0;
}
今天提交的时候发现一个问题,蓝桥杯系统中memset函数的使用头文件加#include<string.h>,我的vs不需要头文件也可以,所以老是忘!!!!