「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
题目
有n种图案的印章,每种印章出现的概率相同。拿m枚印章,那么集齐n种印章的概率是多少。
思路
很明显,这道题目可以用动态规划来解。动态规划是将一个问题分解成一个个子问题来解决,并且每个子问题都是互相有联系的。那么这道题如何一步步化成子问题呢。可以取一个二维数组d[m][n],二维数组的第一列代表的就是拿了几枚印章,之后的每一列就代表的就是拿了这几枚印章,能够收集到几种不同的印章。接下来就可以从一个个子问题来入手,首先,当前拿到的印章数小于要收集的印章种数,那概率必然是0,i<j,d[i][j]=0,如果j=1,不管有几个印章,只收集一种的概率那就是(1/n)的i次方,但是有n种情况,所以概率是(1/n)的(i-1)次方,如果i>j,d[i][j]就之前的三种子情况有关系了,首先是d[i-1][j],少了一个印章,但是种类不变,说明多出来的一个印章种类还是在j个种类中。然后是d[i-1][j-1],少了一个印章,也少了一个印章种类,说明多了一个印章之后选中的一定是原先没有的种类。只有这两种子问题情况,d[i][j]=d[i-1][j](j/n)+d[i-1][j-1]((n-j+1)/n)。最终得出的答案就存储在d[m][n]中。
代码
#include<bits/stdc++.h>
using namespace std;
double d[100][100];
int main(){
int n,m;
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)
d[i][j]=0;
if(j==1)
d[i][j]=pow(p,(i-1));
else
d[i][j]=d[i-1][j]*(1.0*(j)/n)+d[i-1][j-1]*(1.0*(n-j+1)/n);
}
}
printf("%.4lf",d[m][n]);//保留四位小数
return 0;
}
总结
一道题目想用动态规划去求解,从最小的问题开始入手,然后规模逐渐扩大,观察大一些的问题和小问题是否存在联系,如果存在联系,那么就是制定合适的算法思路来完成这道题。