C/C++百题打卡[11/100]——印章[蓝桥杯 算法训练]



一、题目总述

在这里插入图片描述


题目难度:⭐️⭐️⭐️⭐️⭐️


二、题目解析

● 题目读起来很简单,仿佛做起来也很简单。但实际上费脑子。

算法思路——动态规划
设置状态:用 d p [ i ] [ j ] dp[i][j] dp[i][j] 来表示 “买了第 i 张印章后,已经凑齐了其中 j 种的概率”。注意,这里面的 “j 种” 的意思不是 “凑齐了 12、…、j 这几个种” 的意思,而是 “对于 n 种印章来说,凑齐了其中的 j 个种(至于具体是哪 j 种,倒先不管)”

设置状态转移方程:注意一些前提,其中 1 ≤ i ≤ M 1≤i≤M 1iM 1 ≤ j ≤ N 1≤j≤N 1jN。且买到某种印章的概论为 p = 1 N p = \frac{1}{N} p=N1
  [1] 当 i < j 的时候,即是说,买的张数 m 小于印章的种数 n,显然无论如何都不能凑齐,则此时: d p [ i ] [ j ] = 0 dp[i][j]=0 dp[i][j]=0
  [2] 当 i ≥ j 且 j = 1 的时候,即是说,买了第 i 张印章后,已经凑齐了其中的 1 种的概率。也就是说,这个人很倒霉,买了 i 张结果全是某一种印章(至于具体是哪一种,不管。反正是 N N N 种中的一种)。显然: d p [ i ] [ j ] = p i × N = p i × 1 p = p i − 1 , 此 时 j = 1 dp[i][j]=p^i \times N=p^i \times \frac{1}{p}=p^{i-1},此时j=1 dp[i][j]=pi×N=pi×p1=pi1j=1
  [3] 当 i ≥ j 且 j > 1 的时候,即是说,买了第 i 张印章后,已经凑齐了其中的 j 种的概率。这里要又分为两种情况。
    <1> 一种是:买的这第 i 张印章在前面 i-1 次购买中未买到过,那么这次购买就是 再在未买到的 n-(j-1) 种中随便选一种购买。(注,这里为什么是 j-1 可能要多花时间理解一下)则: d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] × [ n − ( j − 1 ) ] × p dp[i][j]=dp[i-1][j-1]\times[n-(j-1)]\times p dp[i][j]=dp[i1][j1]×[n(j1)]×p
    <2> 另一种是:买的这第 i 张印章在前面 i-1 次购买中已买到过了,那么这次购买就是 再在已经买到的 j 种中随便选一种购买。(注,这里为什么是 j 也可能要多花时间理解一下)则: d p [ i ] [ j ] = d p [ i − 1 ] [ j ] × j × p dp[i][j]=dp[i-1][j]\times j \times p dp[i][j]=dp[i1][j]×j×p
  然后把这两种情况加起来即是,当 i ≥ j 且 j > 1 的时候的 “状态转移方程”: d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] × ( n − j + 1 ) × p + d p [ i − 1 ] [ j ] × j × p dp[i][j]=dp[i-1][j-1]\times (n-j+1) \times p+dp[i-1][j]\times j \times p dp[i][j]=dp[i1][j1]×(nj+1)×p+dp[i1][j]×j×p



三、完整代码[C++]

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int N, M;
double dp[25][25];
int main()
{
	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;
			}
			else if (j == 1)
			{
				dp[i][j] = pow(p, i - 1);
			}
			else if (j > 1)
			{
				dp[i][j] = dp[i - 1][j - 1] * (N - j + 1) * p + dp[i - 1][j] * j * p;
			}
		}
	}
	printf("%.4f", dp[M][N]);
	return 0;
}


四、做题小结与感慨

● 动态规划的题,难就难在找 “状态” 和 “状态转移方程”。

● 总结一点关于 dp 的题的一点规律:一般都是从简单地推导开始。就像上面的解析一样,先考虑 i<j 的情况,然后再在 i≥j 的基础上找 j=1 的情况,最后才考虑 j>1 的情况。

在这里插入图片描述



五、参考附录

[1] 原题地址:印章.


C/C++百题打卡[11/100]——印章[蓝桥杯 算法训练]
标签:动态规划

不定期更新   
   2022/3/30   

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一支王同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值