蓝桥杯算法训练—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)

题解:此题采用动态规划的方法求解,动态规划的三要素为:最优子结构,边界和状态转移函数。

image-20220324084952832

有关印章问题的思考:

对于本题,令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}$)。

综上,这两种情况加起来即为完整的状态转移函数。

posted @ 2022-03-24 17:28  zhoupaopaoer  阅读(704)  评论(0)    收藏  举报