组合数学相关

Number数论

组合数学相关

  • 一、排列问题
  • 1、排列数
  • 2.可重排列数
  • 3.圆排列
  • 4、不尽相异元素全排列
  • 二、组合问题
  • 1.组合数
  • 2.可重组合数

一、排列问题

1、排列数( A(n,m) )

从n个不同元素种取出m(m≤n)个元素的所有不同排列的个数,叫做从n个不同元素种取出m个元素的排列数,用A(n,m)表示。

排列数公式
A(n,m) =n (n−1) (n−2) ⋯ (n−m+1) = n! / (n−m)!, n,m∈N+,并且m≤n
(规定0!=1)
推导:把n个不同的元素任选m个排序,按计数原理分步进行
取第一个:有n种取法;
取第二个:有(n−1)种取法;
取第三个:有(n−2)种取法;
……
取第m个:有(n−m+1)种取法;
根据分步乘法原理,得出上述公式。

排列数性质
A(n, m) = nA(n−1, m−1) : 可理解为“某特定位置”先安排,再安排其余位置。
A(n, m) = mA(n−1, m−1) + A(n−1, m) 可理解为:含特定元素的排列有mA(n−1, m−1),不含特定元素的排列为A(n−1, m)。

ll inv[maxn * maxn],fac[maxn * maxn];
void init(){
	int n = 5000 * 5000;
	fac[0] = 1;
	for(int i=1;i<=n;i++){
		fac[i] = fac[i-1] * i % mod;
	}
	inv[1] = 1;
	for(int i=2;i<=n;i++){
		inv[i] = (mod - mod / i) * inv[mod % i] % mod;
	}
	inv[0] = 1;
	for(int i=1;i<=n;i++){
		inv[i] = inv[i] * inv[i-1] % mod;
	}
}

ll C(ll n,ll m){
	return fac[n] * inv[m] % mod * inv[n-m] % mod;
}

ll A(ll n,ll m){
	return fac[n] * inv[n-m] % mod;
}

如果需要打印或者需要用到产生的排序序列,可以使用dfs的方法进行搜索,设置一个变量wei,用来表示已经排好了几位,wei从0开始,如果wei == m,说明已经排好了m个数,输出就好了,具体代码如下:

计算A(3,2):
3 2
6
1 2
1 3
2 1
2 3
3 1
3 2

int vis[10001];//查看该数字是否被访问过
int ans[10001];//存储已经排好位序的数
void A(int n,int m,int wei){
	if(wei == m){//已经排好m个数
		for(int i=0;i<m;i++){
			 cout << ans[i] << " ";
		}
		cout << endl;
	}
	else{
		for(int i=1;i<=n;i++){
			if(!vis[i]){
				ans[wei] = i;
				vis[i] = 1;
				A(n,m,wei+1);
				vis[i] = 0;//注意回溯
			}
		}
	}
} 
2、可重排列数

从 n 个物品中可重复的取 m 个物品,情况种类是 nm;
第一次取可能的选择有 n 种;
第二次取可能的选择有 n 种;
……
第m次取可能的选择有 n 种;
所以总共的情况种类有 nm种。

3、圆排列

百度百科:循环排列(circular permutation)亦称圆排列、环排列等。是排列的一种,指从n个不同元素中取出m(1≤m≤n)个不同的元素排列成一个环形,既无头也无尾。两个循环排列相同当且仅当所取元素的个数相同并且元素取法一致,在环上的排列顺序一致。
实例:在日常生活中和实际应用中,有时需要将元素排在封闭的曲线上。例如,庆祝节日将彩色电灯排成一个五角星形或一个圆环形;展览会展出的商品中,有用钻石穿成的项圈和臂镯;开展文娱活动时,往往围成一个圆环形进行演唱;成品加工时,有的工序安排一个圆环形,进行流水操作,像这样元素环绕在一条封闭曲线上的排列,叫做循环排列。

首先从n个物品中选出m个物品,情况可能的种类有C(n,m),然后对这选出来的m个物品进行全排列 A(m,m) = m!,因为要保证连成一个环之后不能重复,以123为例,123,231,312都是同一组圆排列,所以每三组便能总结成为一组,同理可知m个物品的全排列每m组便只有一组是有效的,其余的(m-1)组都是重复的,所以有效的种类数有 m! / m = (m-1)!,综上所述,从n数中选取m个数进行圆排列的情况种类有 C(n,m) * (m-1)! = A(n,m)/m

long long circular(int n,int m){
	long long sum = 1;
	for(int i=0;i<m;i++){
		sum *= n;
		n--;
	}
	return sum/m; //return A(n,m)/m;
}
4、不尽相异元素全排列

如果在 n 个元素中有 n1 个元素相同,又有 n2 个元素相同,……又有 nm 个元素相同(n1 + n2 + …… + nm <= n),那么把这 n 个元素进行排列的种类有:
在这里插入图片描述

二、组合问题

1、组合数

在这里插入图片描述
//原始的代码

long long C(int a,int n,int mod){
	long long ans = 1;
	for(int i=1;i<=a;i++){
		ans *= (n-i+1)/i;
		ans %= mod;
	}
	return ans;
}

//进阶版

ll inv[maxn * maxn],fac[maxn * maxn];
void init(){
	int n = 5000 * 5000;
	fac[0] = 1;
	for(int i=1;i<=n;i++){
		fac[i] = fac[i-1] * i % mod;
	}
	inv[1] = 1;
	for(int i=2;i<=n;i++){
		inv[i] = (mod - mod / i) * inv[mod % i] % mod;
	}
	inv[0] = 1;
	for(int i=1;i<=n;i++){
		inv[i] = inv[i] * inv[i-1] % mod;
	}
}

ll C(ll n,ll m){
	return fac[n] * inv[m] % mod * inv[n-m] % mod;
}

ll A(ll n,ll m){
	return fac[n] * inv[n-m] % mod;
}

//预处理好数据直接调用

ll inv[maxn * maxn],fac[maxn * maxn];
void init(){
	int n = 5000 * 5000;
	fac[0] = 1;
	for(int i=1;i<=n;i++){
		fac[i] = fac[i-1] * i % mod;
	}
	inv[1] = 1;
	for(int i=2;i<=n;i++){
		inv[i] = (mod - mod / i) * inv[mod % i] % mod;
	}
	inv[0] = 1;
	for(int i=1;i<=n;i++){
		inv[i] = inv[i] * inv[i-1] % mod;
	}
}

ll C(ll n,ll m){
	return fac[n] * inv[m] % mod * inv[n-m] % mod;
}

ll A(ll n,ll m){
	return fac[n] * inv[n-m] % mod;
}

组合数相应的一些性质:
在这里插入图片描述
组合数求和公式

2、可重组合数

真的是被这个问题困扰了快一天(瑟瑟发抖),一共有三个问题情境,先说一个我个人认为比较好入手的点吧:

从n个数中选择r个数,每次选择的数可以重复,一共有多少种可能的情况?
类似于拿取小球可放回,但是如果我们一开始这样将问题联系在一起很容易走入一个难点,第一次抽取的可能有n种,第二次也有n种可能……所以抽取r次共有 nr 种可能性,然后我们就进入到了最头疼的去重了,我们就要进行分类讨论了,不仅要对n和r的大小进行讨论,也要对1~r的不同数进行讨论,这条路走不通,换种思维,既然是组合,那么同一组数的不同排列都属于同一种组合,那么我们把这选出来的r个数从小到大排好:{ a1,a2,a3……ar },取出的这组数的取值范围是1 ~ n,我们将这组数从0 ~ r-1 进行排序,所以我们每一次选出的一组数都由两部分数构成,将这两部分数加起来所以每个数对应的序号是1 ~ n+r-1,所以我们研究的问题就变成了从这n+r-1个数中选取r个,所以情况的种类数是C(n+r-1,r)。可能有点拗口和难以理解,希望这个视频可以帮助理解,清华还是强!!!视频讲解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值