印章 (dp&详解)

问题描述:

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

输入格式:

  一行两个正整数n和m

输出格式:

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

样例输入:

2 3

样例输出:

0.7500

数据规模和约定:

  1≤n,m≤20

解题思路:

一共有m张印章,n种图案,每种图案的概率p=1/n;

现有i张印章,i张有j种图案,即dp[i][j]为i张印章共j种图案的概率(i张印章凑齐j种图案的概率)。

① 当 i < j 时,只有i张印章无法凑齐j种图案,即dp[i][j]=0;

② 当 j = 1 时,

                当i = 1 时,满足i张印章j种图案(一张一种图案)dp [i] [j] = dp [1] [1] = 1;

                当i > 1 时,如果满足 i 张印章j种图案( i 张一种图案),需要 i 张印章都一样,每个图案的概率都是dp [i] [1] = p^i;因为我们的图案不指定哪一种,所以我们的dp[i] [j]是n种图案的概率之和,就是p^i*n,因为p = 1/n;所以dp [i] [1] = p^(i-1) 。

③ 当 j > 1 时,

                如果i-1张印章中,已经凑齐 j 种图案,第 i 张与前(i - 1)张中的一种图案相同,故满足条件;那么满足条件的第 i 张印章的概率为 j / n ,即dp[i][j] = dp [i-1] [j] *(j / n)=dp [i-1] [j] *j * p;

                如果i-1张印章中,已经凑齐j-1种图案,第i张正好为第 j 种图案(与前j-1种不同),故满足条件;那么满足条件的第 i 张印章的概率为 (n - (j-1))/ n =(n-j+1)*p,即dp[i][j] = dp [i-1] [j-1] *(n-j+1)*p。

                故此时满足 i 张印章j种图案的概率为上述两种情况之和,即dp[i] [j] = dp [i-1] [j] *j * p +  dp [i-1] [j-1] *(n-j+1)*p 。

#include <bits/stdc++.h>
using namespace std;
double dp[30][30];
int main(){
    memset(dp, 0, sizeof(dp));
    int n,m;
    cin>>n>>m;
    double p = 1.0 / n;

    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            //不可能满足条件
            if(i<j) dp[i][j]=0;
            if(j==1){
                //i张印章一种图案的概率
                dp[i][j]=pow(p,i-1);
            }
            else {
                //i张印章满足j种图案的概率
                dp[i][j]=dp[i-1][j]*(j*p)+dp[i-1][j-1]*(n-j+1)*p;
                
            }
        }
    }
    //保留4位小数输出
    cout.setf(ios::fixed);
    cout<<fixed<<setprecision(4)<<dp[m][n]<<endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值