印章问题(蓝桥杯) C语言

问题描述

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

输入格式

一行两个正整数n和m

输出格式

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

样例输入

2 3

样例输出

0.7500

数据规模和约定

1≤n,m≤20

解题思路

用动态规划的思想
1:状态表示:dp [ i ] [ j ]表示的是在买 i 张印章时小A集齐 j 种印章的概率.
2:状态转移方程 : dp[i][j] = (n - (j - 1)) * p * dp[i - 1][j - 1] + j * p * dp[i - 1][ j ]; ,现在可能读不懂下面有详细解释。
3,填表顺序:从从左到右,从上到下。

假设买 i 张印章时集齐了 j 种印章。
小A 买印章只有两种可能,一是与前面买的相同(与前面买的印章重复了),二是与前面的印章不同(与前面买的印章没有重复)。
在这的基础上分三种情况

a.当 i < j 时,也就是买的印章小于印章的种类,那肯定集齐的概率为 0 。
b.当 j==1,i <= m 时,也就是说买 i 张印章集齐一张印章,dp[1][1]=1表示买一张集齐一张的概率是 1,当 i >1 时,dp [ i ] [ j ]=(1/n) * (n-1) 。这样理解:假设我买了 3 张印章,这三张印章都是一样的,从第二张开始,第二张与第一张相同的概率是 1/3 ,第三张与第二张相同的概率也是 1/3,所以 dp[3][1]=(1/3) * (1/3) = (1/3) * ( 3-1) = (1/n) * (n-1) 。
c. 剩下的情况 i >= j , j > 1 时,也就是买的印章大于等于印章的种类且集齐的印章不为 1 ,如果 j 为 1 就是情况 b 。买第 i 张印章时有两种情况 第一种是买的印章没有重复, dp[ i ][ j ] = (n - (j - 1)) * p * dp[i - 1][j - 1],(n - (j - 1)表示没有买到的印章种数,用印章种数减去集齐的印章种数,p 就是每一种印章的概率 1/n ,dp[i - 1][j - 1] 表示上一次买印章集齐了 j -1 张,第二种情况是买到重复的印章, dp[ i ][ j ] = j * p * dp[i - 1] [ j ] , j 表示买到的印章种数,p 就是每一种印章的概率 1/n, dp[i - 1] [ j ]表示上一次买印章集齐了 j 张。

代码

#include<stdio.h>
#include<math.h>

int main()
{
	int m, n;
	scanf("%d%d", &n, &m);//2 3
	float dp[21][21] = { 0.0 }, p = 1.0 / n;
	int i = 1,j = 1;
	dp[1][1] = 1;
	for (i = 1; i <= m; i++)//m=3
	{
		for (j = 1; j <= n; j++)//n=2
		{
			if (i < j)
				dp[i][j] = 0;
			if (j == 1)
				dp[i][j] = pow(p, i - 1);
			else
			{
					dp[i][j] = (n - (j - 1)) * p * dp[i - 1][j - 1] + j * p * dp[i - 1][j];
			}
			    
		}
		
	}
	
	printf("%.4f", dp[m][n]);
	return 0;
}
  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值