排列组合 HDU1521 (指数型生成函数模板)
作者:互联网
题意:
有n种物品,并且知道每种物品的数量。要求从中按顺序选出m件物品的方案数。例如有两种物品A,B,并且数量都是1,从中选2件物品,则排列有"AB","BA"两种。
思路:
显然是一个多重集排列数问题,需要用指数型生成函数。
多重集排列数:
k种物品,个数分别为\(a_1,a_2,a_3...a_k\)。\(\sum{a_i}=n\)则按顺序摆放所有物品的方案数为\(n!/\prod{a_i!}\)
令\(G(x)=\prod(1+x/1!+x^2/2!+x^3/3!+....+x^{a_i}/a_i!)\)
最后得到\(G(x)=1+a_1*x/1!+a_2*x^2/2!+....a_p*x^p/p!\)
其中\(a_p\)就是从所有物品中选出p件物品的方案数,因此实际上只要求其中的一个系数(即\(a_m\)),利用二维DP求解就可以(背包问题),如果空间过大可以用滚动数组。
#include <bits/stdc++.h>
using namespace std;
double fac[15];
void getfac() {
fac[0] = 1;
for (int i = 1; i <= 10; i++) {
fac[i] = fac[i - 1] * i;
}
}
double dp[15][15];
int num[15];
int main() {
getfac();
int n, m;
while(cin >> n >> m){
memset(dp,0,sizeof(dp));
for (int i = 1; i <= n; i++) {
cin >> num[i];
}
for (int i = 0; i <= num[1]; i++) {
dp[1][i] = 1.0 / fac[i];
}
for (int i = 2; i <= n; i++) {//枚举第几项
for (int j = 0; j <= m; j++) {//枚举之前选了几个
for (int k = 0; k <= num[i] && j + k <= m; k++) {//枚举当前项选几个
dp[i][j + k] += dp[i - 1][j] / fac[k];
}
}
}
double ans = dp[n][m] * fac[m];
printf("%.0f\n", ans);
}
}
标签:件物品,HDU1521,int,多重集,dp,物品,排列组合,prod,模板 来源: https://www.cnblogs.com/ucprer/p/12269304.html