蓝桥杯-算法-印章问题

这个题真的顶啊!

思路:

n种图案,m张印章,每一个图案的概率是1/n,这个概率以后用P表示

首先我们定义dp[i][j]是买了i张印章(对应于上面的m),凑齐j种图案的概率(对应于上面的n)

然后是推导:

1.如果i<j的话,说明无论买多少印章,都不能凑齐j种图案,所以概率我们就知道是0,所以二维数组dp[i][j]=0

2.如果j=1,说明买i张印章,凑齐一种的概率

这里分成两种情况讨论。

①如果j=1,说明,买一张凑齐一种的概率,这个概率肯定是1

②如果j>1,说明买j张,凑齐一种的概率是多少。

这里详细点,想一想哈,我们如果买两章,也就是j=2,我们凑齐一种的概率是不是应该这样想:p*p*n。这里的思路是:我们要凑齐一种的概率,但是我们抽了两张,每一张的概率是不是p,两张的概率是不是p*p。但是为什么乘n呢,这样想哈,我们一共有n种印章,每一种的概率是不是都是一样的,所以凑齐的这一个就有可能是n中印章的任意一种。所以得乘一个n

3.接下来是普遍情况了。

我们凑得印章都是随机的,我们买之前是不知道下一个是哪种类别的

所以,如果下一张是之前已经存在过得印章的话(也就是前面买的i-1张已经凑齐了j种,接下来的第i张就是重复前面的印章了),所以这个重复的印章再被抽取的时候,它的概率就是j*p(再详细点,前面已经有了j种了,我们此时假设的是,与之前的重复了,而与每一个重复的概率都是p,所以这里是j*p)

这里的式子是:

dp[i][j] = dp[i-1][j] * (j/n) = dp[i-1][j] *(j*p)

4.然后再就是抽取的印章不是重复的情况了

这个说明前i-1张我们凑齐了j-1种,而第i张,也就是接下来的这一张就是要凑齐的一种,但是我们不确定这一个出现的是没出现印章中的哪一种(有点儿绕,慢慢想一下)。因为前面已经出现了j-1种,所以还有n-(j-1)种没有出现。而接下来的这个只要是这没有出现的一种就行了,这个时候凑齐这一种的概率就是(n-j+1)*p

这里的式子就是:

dp[i][j] = dp[i-1][j-1]*(n-(j-1))/n = dp[i-1][j-1]*(n-j+1)*p

所以对于dp[i][j]这里的情况,就是3,4两种情况相加了。

代码是借鉴的其余博客,未亲自编写


#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std; 
double dp[30][30];
int main(void)
{
int n,m;
cin>>n>>m;
double p=1.0/n;
memset(dp,0,sizeof(dp)); 
for(int i=1;i<=m;i++)//i张印章 
{
for(int j=1;j<=n;j++)//j种图案 
{
if(i<j)//不可能凑齐 
{
dp[i][j]=0;
}
if(j==1)//j只要所有图案中的一种就可以了,所以我们(1/n)^i还要再乘n,就是p^i-1 
{
dp[i][j]=pow(p,i-1);
}
else//买了i张凑齐j种,第i张 要么和之前凑齐的一样,要么不一样 
{
dp[i][j]=dp[i-1][j]*(j*p)+dp[i-1][j-1]*(n-j+1)*p;
}
 } 
 
} 
printf("%.4lf\n",dp[m][n]);
return 0;
} 
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值