精华内容
下载资源
问答
  • Python 计算组合数C(n,i),即从n个元素中任选i个,有多少种选法
    千次阅读
    2020-11-20 19:53:08

    1 defC(n, i):2 #isinstance(object, classinfo)

    3 #如果参数object是classinfo的实例,或者object是classinfo类的子类的一个实例,

    4 #返回True。如果object不是一个给定类型的的对象, 则返回结果总是False。

    5 if not (isinstance(n, int) and isinstance(i, int) and n >=i):6 print('n and i must be integers and n must be larger than or qual to i.')7 return

    8 result = 1

    9 Min, Max = sorted((i, n -i))10 for i in range(n, 0, -1):11 if i >Max:12 result *=i13 elif i <=Min:14 result /=i15 returnresult16

    17 print(C(4, 2))

    更多相关内容
  • 计算组合数的三方式

    千次阅读 多人点赞 2020-03-19 02:19:52
    本文将详细介绍计算组合数的三方式,这三方式分别适用于不同的场景。

    摘要

    本文主要介绍计算组合数的三种方式,这三种方式分别适用于不同的数据范围,其中涉及到了数论中的乘法逆元和费马小定理,卢卡斯定理。

    递推

    当数据范围小于等于 3000 3000 3000左右时,可直接根据组合数的一个性质: C ( n , m ) = C ( n − 1 , m ) + C ( n − 1 , m − 1 ) C(n, m) = C(n-1,m) + C(n-1, m-1) C(n,m)=C(n1,m)+C(n1,m1)直接递推计算,时间复杂度为 O ( n 2 ) O(n^2) O(n2).

    public static void get_C(int[][] arr){
        for(int i = 1; i <= MAXN; i++){
            for(int j = 1; j <= MAXN; j++){
                if(j == 1) arr[i][j] = i;
                else arr[i][j] = (arr[i-1][j] + arr[i-1][j-1])%1000000007;
            }
        }
    }
    

    预处理阶乘

    当数据范围小于等于 1 0 5 10^5 105左右时,我们要采取更快的方式计算组合数。

    组合数公式: C ( n , m ) = C(n, m) = C(n,m)= n ! m ! ( n − m ) ! {n!}\over{m!(n-m)!} m!(nm)!n!

    如果我们可以预处理出所有阶乘,然后根据这个公式就可以在 O ( 1 ) O(1) O(1)的时间复杂度内求出组合数,预处理所有阶乘的时间复杂度是 O ( n ) O(n) O(n), 所以总的时间复杂度就是 O ( n ) O(n) O(n)

    但是有一点需要注意的是:当结果很大需要对阶乘取模时,除法并不满足取模分配律。

    也就是说: ( n ! m ! ( n − m ) ! {n!}\over{m!(n-m)!} m!(nm)!n!) % P ≠ \%P \neq %P= n ! % p ( m ! ( n − m ) ! ) % p {n!\%p}\over{(m!(n-m)!)\%p} (m!(nm)!)%pn!%p

    那怎么办呢,我们既然必须要对其取模,还必须要用阶乘,不用除法怎么算呢?这要感谢伟大的前人发现了乘法逆元这个神奇的东西。可以将除法取模转化为乘法取模,乘法是满足取模分配律的。

    那么什么是乘法逆元呢?

    乘法逆元

    对于一个整数a,如果 a ∗ b ≡ 1 ( m o d a*b≡1(mod ab1(mod p ) p) p),则在模 p p p的意义下:

    a 是 b 的 逆 元 , b 是 a 的 逆 元 a是b的逆元,b是a的逆元 abba。但此条件成立的前提是 a , p 互 质 , 即 g c d ( a , p ) = 1 a,p互质,即gcd(a,p)=1 apgcd(a,p)=1

    这里暂且不说乘法逆元如何证明,只需要知道它怎么求,怎么用就可以了。

    乘法逆元的计算方法:

    乘法逆元有好几种求法,这里只介绍用费马小定理求逆元。

    费马小定理:

    如果 a a a p p p互质,则有: a p − 1 ≡ 1 ( m o d a^{p-1}≡ 1 ( mod ap11(mod p ) p ) p)

    这个式子是不是和乘法逆元的式子特别相似:

    a ∗ b ≡ 1 ( m o d a*b≡1(mod ab1(mod p ) p) p)
    a p − 1 ≡ 1 ( m o d a^{p-1}≡ 1 ( mod ap11(mod p ) p ) p)
    对于两个式子,就差了一个 b b b

    我们可以将 a p − 1 ≡ 1 ( m o d a^{p-1}≡ 1 ( mod ap11(mod p ) p ) p)转化为:
    a ∗ a p − 2 ≡ 1 ( m o d a*a^{p-2}≡ 1 ( mod aap21(mod p ) p ) p)

    这样,我们就得到了 a a a p p p的乘法逆元就是 a p − 2 a^{p-2} ap2。我们可以用快速幂来求 a p − 2 a^{p-2} ap2


    好了,知道了乘法逆元怎么用,怎么求,我们就可以来计算 n ! m ! ( n − m ) ! {n!}\over{m!(n-m)!} m!(nm)!n! % p \%p %p 了。

    对于 n ! m ! ( n − m ) ! {n!}\over{m!(n-m)!} m!(nm)!n! % p \%p %p,我们可以预处理出所有阶乘,和所有阶乘%p的逆元。

    代码:

    public static long qmi(long a, long b, long p){ // 快速幂求逆元
        long res = 1;
        while(b != 0){
            if((b&1) == 1){
                res = res * a % p; 
            }
            b >>= 1;
           a = a * a % p;
        }
        return res;
    }
     public static void Init(){
         infact[0] = 1; // 存储逆元
         fact[0] = 1;
         for(int i = 1; i <= 100000; i++){
             fact[i] = fact[i-1] * i % mod; 
             infact[i] = infact[i-1] * qmi(i, mod - 2, mod) % mod;
        }
    }
    

    对于 infact[i] = infact[i-1] * qmi(i, mod - 2, mod) % mod;这行代码可能有些同学会有点迷,下面举个例子就能懂了。
    例如:
    ( 3 ∗ 4 ) p − 2 % p = 3 p − 2 % p ∗ 4 p − 2 % p (3*4)^{p-2} \% p=3^{p-2}\%p*4^{p-2}\%p (34)p2%p=3p2%p4p2%p
    所以,上述代码显然是成立的。

    然后预处理完所有的阶乘和阶乘的逆元之后,就可以直接求组合数了。
    设一共有n组数据,求每组数据的组合数。完整代码:

    import java.io.*;
    import java.util.*;
    
    public class Main{
        static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
        
        static final int N = 100005, mod = 1000000007;
        static int n;
        static long[] fact = new long[N];
        static long[] infact = new long[N];
        
        public static int Int(String s){
            return Integer.parseInt(s);
        } 
        
        public static long qmi(long a, long b, long p){
            long res = 1;
            while(b != 0){
                if((b&1) == 1){
                    res = res * a % p; 
                }
                b >>= 1;
                a = a * a % p;
            }
            return res;
        }
        
        public static void Init(){
            infact[0] = 1;
            fact[0] = 1;
            for(int i = 1; i <= 100000; i++){
                fact[i] = fact[i-1] * i % mod; 
                infact[i] = infact[i-1] * qmi(i, mod - 2, mod) % mod;
            }
        }
        
        public static void main(String[] args)throws Exception{
            n = Int(in.readLine());
            Init();
            
            for(int i = 0; i < n; i++){
                String[] s = in.readLine().split(" ");
                int a = Int(s[0]);
                int b = Int(s[1]);
                out.write((((long)fact[a] * infact[b] % mod * infact[a-b]%mod)%mod) + "\n");
            }
            out.flush();
        }    
    }
    

    卢卡斯定理求组合数

    如果数据范围非常大,在 1 0 18 10^{18} 1018内的话,用O(n)的方式也会超时了,我们需要另辟蹊径,伟大的前人又发现了一个神奇的东西:卢卡斯定理

    卢卡斯定理: C ( n , m ) % p = C ( n / p , m / p ) ∗ C ( n % p , m % p ) % p C(n,m)\%p=C(n/p,m/p)*C(n\%p,m\%p)\%p C(n,m)%p=C(n/p,m/p)C(n%p,m%p)%p

    时间复杂度是: O ( l o g p ( n ) ∗ p ) , p 必 须 是 质 数 O(log_p(n)*p),p必须是质数 O(logp(n)p),p

    所以当 n , m n,m n,m小于p时,我们就直接根据 n ! m ! ( n − m ) ! {n!}\over{m!(n-m)!} m!(nm)!n! % p \%p %p并利用乘法逆元直接计算组合数的值,当 n , m n,m n,m大于p时我们就递归计算 C ( n / p , m / p ) ∗ C ( n % p , m % p ) % p C(n/p,m/p)*C(n\%p,m\%p)\%p C(n/p,m/p)C(n%p,m%p)%p的值

    代码:

    import java.io.*;
    import java.util.*;
    
    public class Main{
        static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
        
        static final int N = 100005, mod = 1000000007;
        static int n;
        static long[] fact = new long[N];
        static long[] infact = new long[N];
        
        public static long Int(String s){
            return Long.valueOf(s);
        } 
        
        public static long qmi(long a, long b, long p){
            long res = 1;
            while(b != 0){
                if((b&1) == 1){
                    res = res * a % p; 
                }
                b >>= 1;
                a = a * a % p;
            }
            return res;
        }
        
        public static long C(long a, long b, long p){
            long res = 1;
            for(long i = 1, j = a; i <= b; i++, j--){
                res = res * j % p;
                res = res * qmi(i, p-2, p) % p;
            }
            return res;
        }
        
        public static long lucas(long a, long b, long p){
            if(a < p && b < p){
                return C(a, b, p);
            }
            else return C(a%p, b%p, p) * lucas(a/p, b/p, p) % p;
        }
        
        public static void main(String[] args)throws Exception{
            n = (int)Int(in.readLine());
            
            for(int i = 0; i < n; i++){
                String[] s = in.readLine().split(" ");
                long a = Int(s[0]);
                long b = Int(s[1]);
                long p = Int(s[2]);
                out.write(lucas(a, b, p) + "\n");
            }
            out.flush();
        }    
    }
    
    展开全文
  • 通过Python计算组合

    千次阅读 2020-08-13 10:51:35
    最近在开发一个报表,其中的指标要根据 所选择的 ...那么这29个字段的任意组合,到底有多少种可能呢?之前我预估大概是千万级,下面用python来算一算: import math s =0 for i in range(1,30): n,m = 29,i r

    最近在开发一个报表,其中的指标要根据 所选择的 维度及属性字段,来动态计算,也就是没办法预先把结果算好。

    维度及属性字段共29个,那么总共产生的组合个数为:29个中选1个的组合数,29个中选2个的组合数。。。,直到 29中选择29个的组合数,把这些组合数相加,就是总的组合数。

    那么这29个字段的任意组合,到底有多少种可能呢?之前我预估大概是千万级,下面用python来算一算:

    
    import math
    
    s =0
    
    for i in range(1,30):
        n,m = 29,i
        r = math.factorial(n)//(math.factorial(m)*math.factorial(n-m))
        s += r
        print(n,m,'组合数:',r)
    
    print('总的组合数:',s)

    输出结果:

    29 1 组合数: 29
    29 2 组合数: 406
    29 3 组合数: 3654
    29 4 组合数: 23751
    29 5 组合数: 118755
    29 6 组合数: 475020
    29 7 组合数: 1560780
    29 8 组合数: 4292145
    29 9 组合数: 10015005
    29 10 组合数: 20030010
    29 11 组合数: 34597290
    29 12 组合数: 51895935
    29 13 组合数: 67863915
    29 14 组合数: 77558760
    29 15 组合数: 77558760
    29 16 组合数: 67863915
    29 17 组合数: 51895935
    29 18 组合数: 34597290
    29 19 组合数: 20030010
    29 20 组合数: 10015005
    29 21 组合数: 4292145
    29 22 组合数: 1560780
    29 23 组合数: 475020
    29 24 组合数: 118755
    29 25 组合数: 23751
    29 26 组合数: 3654
    29 27 组合数: 406
    29 28 组合数: 29
    29 29 组合数: 1
    总的组合数: 536870911

    最后1行,把上面所有组合数相加,得到总的组合数为:536870911,约为 5.3亿。。。

    当然,这么大的组合数,客户在查报表的时候,绝对不可能会覆盖这所有的组合,最多也就是常用的 几十种吧。

     

    展开全文
  • leetcode Combinations计算有多少组合

    千次阅读 2013-12-24 08:26:29
    递归的另外一写法: void comb2(vector<vector<int> > &v, vector<int> &mv, int n, int k, int start) { if (mv.size() == k) { v.push_back(mv); return; } for (int i = start; i ; i+...

    Combinations

     

    Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

    For example,
    If n = 4 and k = 2, a solution is:

    [
      [2,4],
      [3,4],
      [2,3],
      [1,2],
      [1,3],
      [1,4],
    ]


    典型的递归回溯法,多做形成这个递归回溯头脑,就好办了。

    1 递归一次,填入一个数字

    2 填入的数字,不能是小于当前数字的值,防止重复

    3 回溯:记得pop_back()最后加上的一个数字,回溯到上一层。

    4 结束条件:填写够了k个数字的时候,当前填写完毕,回溯


    vector<vector<int> > combine(int n, int k) 
    	{
    		vector<vector<int> > v;
    		if (k > n || k==0) return v;
    
    		vector<int> mv;
    		comb(v, mv, n, k, 1);
    		return v;
    	}
    
    	void comb(vector<vector<int> > &v, vector<int> &mv, int n, int k, int start)
    	{
    		for (int i = start; i <= n; i++)
    		{
    			mv.push_back(i);
    			if (mv.size() == k)
    			{
    				v.push_back(mv);
    				mv.pop_back();
    				continue;
    			}
    			//i<n条件可以不加,因为递归的时候也自动判断排除这个条件了
    			if (i < n) comb(v, mv, n, k, i+1);
    			mv.pop_back();
    		}
    	}

    递归的另外一种写法:

    void comb2(vector<vector<int> > &v, vector<int> &mv, int n, int k, int start)
    	{
    		if (mv.size() == k)
    		{
    			v.push_back(mv);
    			return;
    		}
    
    		for (int i = start; i <= n; i++)
    		{
    			mv.push_back(i);
    			comb2(v, mv, n, k, i+1);
    			mv.pop_back();
    		}
    	}


    //2014-2-12 update
    	vector<vector<int> > combine(int n, int k) 
    	{
    		vector<vector<int> > rs;
    		if (k<1 || n<k) return rs;
    		vector<int> tmp;
    		helper(rs, tmp, n, k);
    		return rs;
    	}
    
    	void helper(vector<vector<int> > &rs,vector<int> &tmp, int n, int k, int begin = 1)
    	{
    		if (!k)
    		{
    			rs.push_back(tmp);
    			return;
    		}
    		for (int i = begin; i <= n; i++)
    		{
    			tmp.push_back(i);
    			helper(rs,tmp,n,k-1,i+1);
    			tmp.pop_back();
    		}
    	}








    展开全文
  • JAVA算法 几个数排列组合

    千次阅读 2019-08-16 17:35:25
    // 将新的排列组合存放起来 } else { for (int i=start; i; i++) { int temp = nums[start]; // 交换数组第一个元素与后续的元素 nums[start] = nums[i]; nums[i] = temp; permutation(nums, start + 1, end); // ...
  • 组合数c(n,m)计算的四方法

    千次阅读 2019-06-29 21:16:47
    转载自 组合c(m,n)的计算方法 2017年10月13日 ⁄ 综合 ⁄ 共 2603字 ⁄ 字号 小 中 大 ⁄ 评论关闭  ...
  • 问题:计算m个A,n个B可以组合多少种排列问题? 假设:计算3个A,2个B可以组合多少种排列问题? 举例:AAABB BABAA… 方法:采取分割思想将第一个与后面的分开,划分为两部分,变得好解决 第一个字母为A时f(m-1,n...
  • 排列组合公式/排列组合计算公式

    千次阅读 2019-12-09 19:53:03
    排列组合公式/排列组合计算公式 公式P是指排列,从N个元素取M个进行排列。 公式C是指组合,从N个元素取M个进行组合,不进行排列。 N-元素的总个数 M参与选择的元素个数 !-阶乘,如9!=9*8*7*6*5*4*3*2*1 ...
  • 首先这道题目是说,一个数组,例如arr={1,2,3,4,5,6},给定一个n,例如给定4,问:从数组中取4个数一共有多少种组合方式?这个在数学上是排列组合问题。用脑子想的话,可以很快就思路。 例如: 先定下取1...
  • 计算组合数的几方法总结

    万次阅读 多人点赞 2018-08-02 20:57:11
    组合数就是CmnCnmC_n^m,是排列组合中非常重要的一部分,最近做到了几道与计算组合数有关的题,想在此总结一下如何编程计算组合数。 递推(杨辉三角) 先给出递推公式:Cmn=Cmn−1+Cm−1n−1Cnm=Cn−1m+Cn−1m−1C...
  • 组合数的两种计算方法(递推,对数)

    千次阅读 2017-10-05 14:15:43
    组合数 ... 从m个不同元素中,任取n(n≤m)个元素并成一组,叫做从m个不同元素中取出n...所有可能的组合种数就是组合数。组合数的计算公式如下图: 式子中出现了阶乘,而20!=2.4329020081766 * 101
  • 6位数,共有几排列组合的算法,java实现
  • python计算排列组合

    千次阅读 2020-06-29 15:45:20
    一、编写函数计算组合数CinC^{i}_{n}Cni​。
  • 组合数是指从n个不同元素中,任取m(m≤n)个元素并成一组,叫做从n个不同元素中取出m个元素的一个组合;从n个不同元素中取出m(m≤n)个元素的所有组合的个数,叫做n个不同元素中取出m个元素的组合数。用符号c(m,n) ...
  • 编程计算组合

    千次阅读 2019-03-12 11:31:48
    问题 组合数就是[C_n^m],是排列组合中非常重要的一部分,直接按照公式求阶乘会超过int,long的范围,因此在
  • 计算组合数python实现

    千次阅读 2020-04-27 20:59:59
    组合数 1.阶乘的写法 Cnm=AnmAmm=n!(n−m)!∗1m!C_n^m=\frac{A_n^m}{A_m^m}=\frac{n!}{(n-m)!}*\frac{1}{m!}Cnm​=Amm​Anm​​=(n−m)!n!​∗m!1​ # import math # math.factorial() ,math里也自带了阶乘函数 def...
  • Java计算组合数以及生成组合排列

    万次阅读 多人点赞 2018-11-24 00:28:29
    组合计算 公式法 逐个相除法(错误) 逐个相除法修正版 素数幂乘法 基本公式法 平方差连乘法 组合恒等法 简单递归法 杨辉三角法 杨辉三角优化法 二进制法 组合计算小结 获取数组的组合排列 二进制法...
  • 详细总结组合排列的十余算法实现

    万次阅读 多人点赞 2020-02-10 22:37:51
    排列组合的问题,如果没有合适的算法去解决,时间复杂度会相当的大,毕竟阶乘的时间复杂度不仅让人头大,也让他计算机欲罢不能,而且我们遇到排列组合的相关问题的概率相当的大,所以非常必要掌握...
  • python快速计算排列组合,附实例

    千次阅读 2019-06-07 11:14:02
    #调用scipy科学计算包中计算排列组合(permutation and combination)的模块 from scipy.special import perm, comb #从3个人中抽取任意两人去排队抢优衣库,有多少种情形(注意要排队!): p = perm(3,2) #从3...
  • 风险价值(VaR)用于尝试量化指定时间范围内公司或投资组合中的财务风险水平。VaR提供了一段时间内投资组合的最大损失的估计,您可以在各种置信度水平上进行计算
  • c怎么算(排列组合c的计算方法)

    千次阅读 2021-07-01 01:45:57
    C上面1,下面5,怎么算啊??谁能用大白话讲一下基本规律? 我知道C上面.数学表达式是C(n,m)=n!/[m!(n-m)!] 你那么算是对的 C(5,1)=5(下面是总数,上面是出现的次数)....=1*2*3*4*.*nC语言怎么计算一个数有多少位...
  • python计算组合数的两实现方法

    万次阅读 2018-06-20 01:05:27
    import math import itertools from itertools import combinations print(unique) ## [ 1 2 3 4 5 56 78 23] i=0 for combination in combinations(unique, 2): print(combination) ...print(i) ...
  • C语言实现组合式的计算

    千次阅读 2019-04-25 13:33:25
    先挖个坑,整理了一下算法笔记中的思路,具体代码之后补上,点击跳转这个链接里po主码的算法笔记里的代码,本文中引用了里面的部分内容 组合式定义: 性质: 1.C(n,m)=C(n,n-m) 2.C(n,n)=C(0,0)=1 方法一:通过...
  • java 实现数量不限的面值为100,50,20,10,5,1元的纸币,问要组成N(N^6)共有多少种组合方式;其中包括了爆搜的方法和动态规划的方法
  • 1234组成的数字一共多少个?都是什么数字?我先时候一下答案吧。由1、2、3、4组成数字一共能组成的数字340个,这其中包括了重复的数字,而组成不重复的数字一共可以组成64个。这些组成的数字中一位数、两位、三位...
  • 24点为什么一共1820种组合

    千次阅读 2017-01-31 20:54:06
    52张牌选4,共有(52*51*50*49)/(4*3*2*1)=270725种组合, 但是这270725种组合中,包括了点数一样但花色不...如果除去这种因素的话,又共有多少种组合呢?可以这样计算: 4张牌数字都相同的组合共有13种(AAAA,2222,3333.QQQQ,
  • MATLAB计算阶乘、排列数与组合

    万次阅读 2019-03-08 18:30:16
    在1500件产品中400件次品,1100件...但是,计算量较大,于是笔者希望通过MALTAB编程计算出数值。 经查阅得知通过阶乘、排列数的对应命令如下: ——factional(n)或prod(1:n) ——nchoosek(n,k) 笔者天真的以...
  • 前段时间同学问到,如何编程求排列组合数,以及列出所有排列组合形式的算法。乘着放假,写了一实现的方法!怕时间长了,淹没在硬盘里,记录在此! /// /// 计算Int32类型的整数的阶乘,目前最大只能对20以内的...
  • 组合数C(n,m)的四种计算方法

    万次阅读 多人点赞 2018-08-10 10:56:05
    组合c(m,n)的计算方法 2017年10月13日 ⁄ 综合 ⁄ 共 2603字 ⁄ 字号 小 中 大 ⁄ 评论关闭 问题:求解组合数C(n,m),即从n个相同物品中取出m个的方案数,由于结果可能非常大,对结果模10007即可。 共四...
  • 排列组合c怎么算 公式是什么

    千次阅读 2021-06-29 05:26:20
    排列组合c怎么算 公式是什么2020-03-13 13:07:32文/叶丹排列定义,但计算方法只有一,凡是符合这两定义的都用这种方法计算。定义的前提条件是m≦n,m与n均为自然数。下面介绍排列组合c的计算方法及公式,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 734,706
精华内容 293,882
关键字:

如何计算有多少种组合