蓝桥杯 试题 算法训练 印章

试题 算法训练 印章

动态规划:

资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

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

输入格式

一行两个正整数n和m

输出格式

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

样例输入

2 3

样例输出

0.7500

数据规模和约定

1≤n,m≤20

题目意思简洁明了。。。。

动态规划

1.设置状态(看是一维数组还是二维数组,一般的题目都是二维数组,经验之谈)

2.找状态之间的关系,

3.写代码

这其中1,2是最难的,首先把状态想出来这一步就可以劝退很多人了,怎么想状态呢,把我平时做dp的思路跟你们说一下:

首先看题目,有买的印章数和印章种数两个变量,就自然而然地想成二维数组dp[i] [j],数组有了。状态呢?题目要求的是概率嘛,那我们dp数组的值就是概率。那么,i,j怎么说呢?题目说了小A买了m张,要凑齐n种,那么我们就设:dp[i] [j]表示买 i 张凑齐 j 种印章的概率。

这样,状态就大致想出来了!(为什么是大致?因为不确定我们的思路是不是对的,状态是根据题意、经验和感觉设想出来的),可能就是要多做吧。

蓝桥杯 试题 算法训练 印章_第1张图片

状态设想出来,二维数组的表格先画出来(如上图)。然后寻找初始状态(一般都是i == 1,2,3或者j == 1,2,3这种i,j的值很小的)。

题目中有 n 种印章, 每种概率是 1/n;

先来看i:因为买 i 张最多只能凑齐 i 种,所以这种情况概率为0

再来看j=1的时候:

i=1:dp[i] [1]表示的意思是买 i 张凑齐 1 种的概率,很明显 i == 1 && j == 1 的时候dp[1] [1] = 1,因为你买一张是无论如何都可以凑齐一种的,是吧。

i > 1:i > 1 && j == 1. 意思就是买 i 张凑齐 1 种印章的概率,意味着买的这 i 张印章是同一种,概率就是 (1/n)^i,但是,我们这 i 张要么是第一种,要么是第二种…( 要么是第k种 ,1 <= k <= n )。最后还要乘上n,所以这个情况 dp[i] [j] = (1/n)^(i-1)

初始状态大致就上面这些了:↑

最后来看中间的状态 dp[i] [j]:

我们买的第 i 张,有两种状态,一:跟前面买的 i-1 张中有重复的 二:跟前面买的 i-1 张中没有重复的

什么意思呢? 比如:(总共有5种印章,标号1,2,3,4,5) 我正在买第5张,前面四张凑齐了1,2,3,4号,那么第5张如果也是1,2,3,4号中的一个就表示重复的;如果第5张是5号,就表示没有重复的。

一:有重复的:就表明前面买的 i-1 张,已经凑齐了 j 种。dp[i] [j] = dp[i-1] [j] * ( j / n ); j/n是什么意思?

蓝桥杯 试题 算法训练 印章_第2张图片

二:无重复的

前面买的 i-1 张 凑齐了 j-1 种, 我们买的第 i 张与前面的不重复,就又凑齐了一种:

蓝桥杯 试题 算法训练 印章_第3张图片

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

然后把两种情况加起来就是dp[i] [j] 的概率了!!

#include <iostream>
#include <cmath>
using namespace std;
double dp[25][25], p;
int main()
{
	
    //记住是小数啊,要*1.0进行类型转换的
	int n, m;
	cin >> n >> m;
	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 ) {
				dp[i][j] = pow (p, i-1);  //p^(i-1)
			}
			else {
				dp[i][j] = dp[i-1][j] * (j*1.0/n) + dp[i-1][j-1] * ((n-j+1)*1.0/n);
			}
		}
	}
//	cout << "dp\n";
//		for ( int i = 1; i <= m; ++i ) {
//		for ( int j = 1; j <= n; ++j ) {
//			printf("%.2lf  ",dp[i][j]);
//		}
//		cout << endl;
//	}
	
	printf("%.4lf  ",dp[m][n]);
	return 0;
}

总结:

1.数组确定(一维,还是二维,三维,n维也有…一般没有)

2.数组值(题目求什么,我们数组表示的值一般就是什么

3.状态设想 (dp[i] [j]表示 什么什么 i 什么什么 的时候什么什么 j 什么什么的时候

4.初始状态(就是找特殊值,i=1,2,3 j=1,2,3)

5.中间状态 ( i, j 与 i-1, i-2, j-1, j-2…)

6.写代码

你可能感兴趣的:(算法,蓝桥杯,动态规划)