组合数问题

一、组合数简介

        组合数是数学中的一个分支,研究的是从给定的元素集合中选出若干个元素组成子集的方法数。在组合数学中,这些子集被称为组合。组合数用于计算各种排列、组合、选择等问题,是概率、统计学和离散数学等领域的基础。

        组合数通常表示为C(n,k),其中n表示元素集合中的元素数,k表示要从集合中选出的元素数。组合数的计算公式为:C(n,k) = n!/((n-k)!*k!),其中“!”表示阶乘。这个公式的意义是,在n个元素中,选出k个元素的选法数目。

二、组合数相关公式(组合数的应用)

1、组合数公式

C(n, k) = n! / (k! * (n - k)!),其中n表示元素集合中的元素数,k表示选出的元素数。

2、二项式定理

(a + b)^n = C(n, 0) * a^n * b^0 + C(n, 1) * a^(n-1) * b^1 + ... + C(n, k) * a^(n-k) * b^k + ... + C(n, n) * a^0 * b^n。

3、帕斯卡三角形

帕斯卡三角形是一个由组合数构成的三角形。在帕斯卡三角形中,每个数字是由它上方两个数字之和得到的。例如,C(n, k) = C(n-1, k-1) + C(n-1, k)。

4、多项式系数

对于多项式展开式中的各项系数,可以通过组合数来计算。例如,展开式(x + y)^n中,x^k * y^(n-k)的系数为C(n, k)。

5、乘法原理:

如果一个事件发生的方式有m种,另一个事件发生的方式有n种,那么这两个事件同时发生的方式有m * n种。

6、Catalan数(卡特兰数)

用于计算卡特兰数

1、H(n)=C[2n,n]−C[2n,n−1](n=0,1,2,...)

2、H(n)=C[2n,n]/(n+1)(n=0,1,2,...)

相关问题请点击:数论 卡特兰Catalan数-CSDN博客

三、递推公式

组合数的递推公式可以用来计算从n个元素中选择k个元素的组合数,常用的递推公式如下:

C(n, k) = C(n-1, k-1) + C(n-1, k)

这个递推公式表示了从n个元素中选择k个元素的组合数的计算方法。其中C(n, k)表示从n个元素中选择k个元素的组合数。根据这个递推公式,我们可以通过不断缩小问题规模,直到达到基本情况,从而计算出组合数的值。

基本情况为:
C(n, 0) = 1 (选择0个元素)
C(n, n) = 1 (选择所有n个元素)

通过递推公式和基本情况,我们可以使用递归或者动态规划等方法来计算组合数。

经典应用:杨辉三角

 j=0j=1j=2j=3j=4j=5
i=01     
i=111    
i=2121   
i=31331  
i=414641 
i=515101051
i=6.........

由动态规划算法可以得到杨辉三角!!!

四、相关算法

1、暴力算法(由组合数公式C(n, k) = n! / (k! * (n - k)!)得到)

核心思想:

分母denominator=1*2*3*·····*n

分子numerator=n*(n-1)*(n-2)*······*(n-k+1)

实现代码:

#include<bits/stdc++.h>
using namespace std;
long long combination1(int n,int k){
	if (k==0||n==k)
		return 1;//C(n,0)和C(n,n)的情况
	int denom=1;
	int numer=1; 
	for(int i=1,j=n;i<=k,j>=n-k+1;i++,j--)
	{
		denom*=i;//分母 
		numer*=j;//分子	
	}
	return numer/denom; 
}
int main(){
	int n,k;
	cin>>n>>k;
	cout<<combination1(n,k);
	return 0;
}

时间复杂度:

求单个数:

时间复杂度为O(k),其中k为选出的元素数。在for循环中,i和j都是从1开始或从n开始递增或递减的,因此循环次数与k成正比。在循环过程中,每次需要进行一次乘法运算和一次除法运算,因此总的时间复杂度为O(k)。可以看出,这个算法的时间复杂度较低,适用于计算小规模的组合数。但对于较大的n和k,可能会导致整数溢出的问题。

求杨辉三角:

使用这个函数求解杨辉三角形的每个元素,那么时间复杂度将是O(n^3)

其中combination1函数中,由于循环的次数与k成正比,而k在杨辉三角形中最大的取值为n/2,所以时间复杂度为O(n/2)=O(n)。因此,对于每一行的计算,时间复杂度为O(n)。

而遍历杨辉三角需要一个二重循环,总共有n行,所以总的时间复杂度为O(n * n) = O(n^2)

总复杂度就为O(n^3)

2、动态规划(求杨辉三角)

核心思想:

递推公式:C(n, k) = C(n-1, k-1) + C(n-1, k)

实现代码:

#include<bits/stdc++.h>
#define MAX_N 20
#define ll long long
using namespace std;
ll c[MAX_N*2][MAX_N];//存放组合数 
 
ll combination2(int n,int k){
//动态规划求组合数 
	for(int i=1;i<=2*n;i++)
    {
    	c[i][0]=c[i][i]=1;
    	for(int j=1;j<i;j++)
    	{
    		c[i][j]=c[i-1][j]+c[i-1][j-1];
		}
	}
	return c[n][k];
}
int main(){
	int n,k;
	cin>>n>>k;
	cout<<combination2(n,k);
	return 0;
}

时间复杂度:

均为O(n * n) = O(n^2)

3、递归算法

核心思想:

递推公式:C(n, k) = C(n-1, k-1) + C(n-1, k)

实现代码:

#include<bits/stdc++.h>
#define MAX_N 20
#define ll long long
using namespace std;
ll c[MAX_N*2][MAX_N];//存放组合数 
 
long long combination3(int n, int k) {
    if (k == 0 || k == n) {
        return 1;
    } else {
        return combination3(n-1, k-1) + combination3(n-1, k);
    }
}
int main(){
	int n,k;
	cin>>n>>k;
	cout<<combination3(n,k);
	return 0;
}

时间复杂度:

段代码使用递归的方式计算组合数。时间复杂度 min(O(k) , O(n-k))

在这段代码中,每次递归调用都会分为两个子问题,即 combination(n-1, k-1) 和 combination(n-1, k)。因此,递归的深度是 k 或 n-k 中较小的那个。

对于每个递归步骤,除了递归调用外,还有一些简单的比较和加法操作。所以每个递归步骤的计算量是常数级别的。

综上所述,这段代码的时间复杂度是 O(k) 或 O(n-k),具体取决于 k 和 n-k 的大小。

  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值