zoukankan      html  css  js  c++  java
  • 排列组合 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
    ", ans);
    	}
    }
    
  • 相关阅读:
    python之编写购物车(第二天)
    day6作业--游戏人生
    day7 socket网络编程基础
    day7 --socket网络编程基础
    Python类和人类
    day7 socket网络编程
    day7异常处理
    day7面向对象--反射
    day6面向对象--类的特殊成员方法
    使用BigDecimal来进行精确计算
  • 原文地址:https://www.cnblogs.com/ucprer/p/12269304.html
Copyright © 2011-2022 走看看