蓝桥杯算法训练—01印章
算法训练——01印章
问题描述:
共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
输入格式:
一行两个正整数n和m
输出格式:
一个实数P表示答案,保留4位小数
样例输入:
2 3
样例输出:
0.7500
数据规模和约定:
1<=n,m<=20
附上代码:
n,m = map(int,input().split())
#生成了一个25*25的全为0的二维数组
dp = [ [0 for i in range(25)] for j in range(25)]
#买的印章数
for i in range(1,m+1):
#集齐印章种数
for j in range(1,n+1):
if i < j:
#用d[i][j]表示小A集齐n种印章的概率,其中i,j分别表示当前状态的买的印章数目和收集到的种类数目
dp[i][j] = 0
elif j == 1:
dp[i][j] = (1/n) ** (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
s = float(dp[m][n])
print('%.4f' % s)
题解:此题采用动态规划的方法求解,动态规划的三要素为:最优子结构,边界和状态转移函数。

有关印章问题的思考:
对于本题,令d[i] [j]表示小A同学手里的印章数目为i,印章的总种类数目为n时,小A收集j种印章的概率。
边界:
当j=1,i=1时,dp[1] [1]表示小A手里有1枚印章并且集齐了一种的概率,dp[1] [1]=1;
当i>1,dp[i] [1]表示小A手里有i枚印章并且收集到一种类型的概率,也就是说小A手里的这i枚印章全都是一种类型的,但是一共有n种类型,因此$dp[i] [1]=n*(\frac 1n)^{i}=(\frac 1n)^{i-1}$;
还有一种情况就是:当i<j时,小A手里有i枚印章,收集到j种的概率,为0;
状态转移函数:
状态转移函数就是指站到一个这样的递推式,能够正确的表达状态之间的关系,这样就能从初始状态一直往下推了。
中间状态d[i] [j]:从手里有(i-1)枚印章到有i枚印章,可以分为两种情况:
1、拿到的第i枚印章种类,在此之前已经获得,此时dp[i] [j]表示手里已经有j种印章了,由于第i枚与之前的重复,所以上个状态(手里有(i-1)枚印章时,用dp[i-1] [j]表示),已经有了j种印章。因此,dp[i] [j]=dp[i-1] [j]*($\frac jn$);
2、拿到的第i枚印章种类,在此之前没有获得,前面取的了(j-1)种,第i次取的为新的种类的印章,又因为印章一共有n种,所以,第i次取的是n-(j-1)中的一个,因此,dp[i] [j]=dp[i-1] [j-1]*($\frac {n-j+1}{n}$)。
综上,这两种情况加起来即为完整的状态转移函数。

浙公网安备 33010602011771号