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);
    	}
    }
    
  • 相关阅读:
    生成一个平面矩形网格文件
    生成球 使用openMesh 库
    U盘安装可能会遇见UEFI的问题,使用easyBCD安装即可。
    vs 代码格式化
    跨域问题的出现和解决
    代理服务器的作用 和 推荐
    sublime user 配置
    git 大佬的相关配置
    win10 注册
    【BZOJ3566】—概率充电器(树形+概率dp)
  • 原文地址:https://www.cnblogs.com/ucprer/p/12269304.html
Copyright © 2011-2022 走看看