试题 算法训练 印章(C语言版)(官网测试已通过)

问题描述

  共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。

输入格式

  一行两个正整数n和m

输出格式

  一个实数P表示答案,保留4位小数。

样例输入

2 3

样例输出

0.7500

 话不多说先上代码

#include 
#include 
int main()
{
    int n,m;//m<20(张   n>=1(种
    scanf("%d %d",&n,&m);
    double a[25][25];
    int i,j;
    double p=1.0/n;
    for (i=1;i<=m;i++)
    {
        for (j=1;j<=n;j++)
        {
            if(i

首先分析题目:n种印章(额打印章太麻烦,我们后面用牌来代替)一共有m张 求集齐的概率,

很明显这里有三种数据(种数,张数,概率),联想到二维数组,我这里使用的是a[i][j]表示一共i张牌集齐j种的概率,接下来我们需要借助一张表格来分析当然这是我做出来过后画的,便于解析代码。(额我不会打斜线i\j是两种代表行代表j列代表i)

这张表我输入的是两个3(n=3 and m=3)

i(张)\j(种)

1 2 3
1 1 0 0
2 1/3 2/3 0
3 1/9 2/3 2/9

那么问题来了这个表是怎么换算的(这个题与其说是算法题,更像数学题),

首先j(种)>i(张)很明显我们是集不齐的,所以全部是0,

那么当j=1时怎么计算呢?

当i=1时我们买一张肯定会出一种牌,同样这里我们可以有第二种想法(可能不太对,但是以这种思路推导下面比较顺畅),即我们买一张会出一张牌,这是肯定的但是我们是不知道出的哪张牌,所以每张牌被我们抽出来的概率是p=1/n表中n=3同样我们这里的j=1 && i=1 我们也不知道出的是哪张牌所以我们还要乘牌的总数即3所以买一张牌集齐一张的概率是1

i=2我们买了2张牌,而要集齐一张,那么这两张牌必须是重复的那么我们第一张可以是n种之间的任意一张在这里即a,b,c三张(我们使用abc来代替三张牌),而第二张我们需要和第一张保持一样

假设第一张牌时a 那么我们第二张也要是a 两次都抽到a的概率都是1/3所以两次都抽到a的概率为1/3*1/3为1/9但是我们有三张牌a,b,c三种情况我们都需要计算,则1/9还需要乘3所以最后的概率为1/3

当i=3的时候同样和i=2是一样的道理,抽到三张全是a的概率为1/27,但是我们有三张牌,需要乘3则为1/9

到这很明显当j=1时是存在一个通用公式的即a[i][j]=((1/n)^i)*n=p^(i-1)

那么当j=2的时候这个公式是否还适用呢,很明显这个公式已经不适用了,那也没办法啊,该解题还得解啊。

回到a[2][2]和a[3][2]上来,我们的a[i][j]代表的是买了i张牌集齐j种牌,

那么我们其他的情况就只剩两种了,一种是包含重复项比如a[3][2]买了三张牌只集齐了两种牌很明显多的哪张牌和我们集齐的两种已经重复了,而a[2][2]就属于是没有重复的,一共买两张牌,集齐了两张,那么问题来了我们怎么区分这两种情况呢?

不要着急我们接着往下分析,

首先是不重复的,比如a[2][2]这里我们是不是买的第二张,所以我们只需要考虑买的这一次是不是和以前重复就行了,换成a[i][j]是不是就表示我们前面的i-1张已经集齐了j-1种牌,那么我们现在只需要确保这一张不和以前重复再乘上i-1张牌全部不重复的概率,而我们之前已经抽出了j-1张牌,而牌的总数是n,我们剩下还没有抽到的就只有(n-(j-1))种即(n-j+1),而每张卡抽到的概率还是p,则这里的通用公式即为a[i][j]=a[i-1][j-1]*(n-j+1)*p为什么是a[i-1][j-1]呢?

这是因为很明显只有i=j的时候才会有刚好不重复的情况

有重复的:表示前面的 i-1 张里面已经凑齐了 j 种,第 i 张就是重复前面的印章,这个时候前面已经出现过的 j 种印章再出现的时候,它就是 j*p 

这个时候a[i][j] = a[i-1][j] * (j/n) = a[i-1][j] *(j*p)

回到问题上来那么我们怎么区分呢?

答案当然是不需要区分,他们的和就是其概率,比如a[2][2]这种无重复的情况按照有重复的计算他的上一格必定是0,所以相当于还是计算的不重复的,而对于a[3][2]呢?很明显a[3][2]有两种把情况,算是我埋下的一个坑(不知道有没有人发现啊)很好理解,前两次抽到一样的和第三次是不一样是一种情况,前两次不一样那么我们就需要第三次和前面个两次任意一个一样,所以这种类型的格子也是两种情况相加。

所以这两种情况我们都可以用同一个公式即

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

你可能感兴趣的:(蓝桥杯练习,日常总结,ACM练习,c语言,算法,蓝桥杯)