zoukankan      html  css  js  c++  java
  • 【HDU1521】排列组合

    题目链接

    排列组合

    题目描述

    (n)种物品,并且知道每种物品的数量。要求从中选出(m)件物品的排列数。例如有两种物品A,B,并且数量都是(1),从中选(2)件物品,则排列有"AB","BA"两种。

    输入格式

    每组输入数据有两行,第一行是二个数(n),(m)((1 le m),(n le 10)),表示物品数,第二行有(n)个数,分别表示这(n)件物品的数量。

    输出格式

    对应每组数据输出排列数。(任何运算不会超出(2^{31})的范围)

    样例输入

    2 2
    1 1
    

    样例输出

    2
    

    题解

    其他人的题解上写的都是用母函数做,我学了半天也没学会,最后直接去看代码,发现好像就是dp,所以就用dp的方式理解了一下。
    题目要求去(m)个数的排列方案数。
    我们用(dp[i][j])表示前(i)个数中选了(j)个数的排列方案数。
    那么转移方程就是:
    (dp[i][j]=dp[i-1][j-k]*f[j]/(f[j-k]*f[k]))
    (k)表示第(i)个数选择了多少个,
    (f[i])表示(i)的阶乘。
    接下来解释一下转移方程:
    当原来的一个排列方案有(i)个数,这时候加入(k)个数,不考虑加入的数相同的情况下,那么方案数就是(prod_{j=i+1}^{i+k}j)
    接下来我们考虑到加入的数相同,那么加入了(k)个数,多算的方案数就是(prod_{j=1}^{k}j)
    最后我们考虑到dp中(i)的影响只有一层,所以我们可以优化掉一维空间。
    打完了之后没看到有好多组数据,好dark╥﹏╥。
    上代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    long long a[19];
    long long dp[2][19];
    long long f[19];
    int main(){
        while(scanf("%d%d",&n,&m)!=EOF){
            f[0]=1;
            for(int j=1;j<=m;j++)
                f[j]=f[j-1]*j;
            for(int j=1;j<=n;j++)
                scanf("%lld",&a[j]);
            memset(dp,0,sizeof(dp));
            dp[0][0]=1;
            for(int j=1;j<=n;j++){
                for(int k=0;k<=a[j];k++){
                    for(int i=0;i+k<=m;i++){
                        dp[1][i+k]+=dp[0][i]*f[i+k]/(f[i]*f[k]);
                    }
                }
                for(int i=0;i<=m;i++)
                    {dp[0][i]=dp[1][i];dp[1][i]=0;}
            }
            printf("%lld
    ",dp[0][m]);
        }
        return 0;
    }
    
  • 相关阅读:
    python D20 多继承、C3算法、super()
    python D19 约束、日志
    python D18 反射与md5 加密
    python D17 类与类之间的关系
    python D16 成员
    python D15 面向对象
    python D14 内置函数二
    python D13 内置函数
    python D12 生成器以及生成器表达式
    oracle函数
  • 原文地址:https://www.cnblogs.com/linjiale/p/13477434.html
Copyright © 2011-2022 走看看