离散:常用排列组合模型归纳,DFS代码实现

Posted --believe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了离散:常用排列组合模型归纳,DFS代码实现相关的知识,希望对你有一定的参考价值。

一、排列

1.定义

n个元素的集合A中任意选择r个( n ≤ r n\\leq r nr)进行排列称为A的一个r-排列/r-Permutation

n个元素的集合A的r-排列数为
p ( n , r ) = n ( n − 1 ) . . . 1 = n ! / ( n − r ) ! p(n,r)=n(n-1)...1=n!/(n-r)! p(n,r)=n(n1)...1=n!/(nr)!

2.理解

将n个元素选择r个元素出来(无顺序),然后进行全排列(有顺序)。

二、组合

1.定义

n个元素的集合A中任意选择r个( n ≤ r n\\leq r nr)称为A的一个r-组合/r-Combination

n个元素的集合A的r-组合数为

C ( n , r ) = n ( n − 1 ) . . . 1 / r ! = n ! / r ! ( n − r ) ! C(n,r)=n(n-1)...1/r!=n!/r!(n-r)! C(n,r)=n(n1)...1/r!=n!/r!(nr)!

推论:

C ( n , r ) = C ( n , n − r ) C(n,r)=C(n,n-r) C(n,r)=C(n,nr)

2.理解

将n个元素选择r个元素出来(无顺序)。$ C(n,r)=P(n,r)/r!$表示在排列的基础上除以r的全排列(相当于去掉顺序)

三、排列组合常见模型

1.r-可重排列

1.1.定义

n个不同元素的集合A,每个元素都可以重复选取,然后进行排列。

定理1:

n个不同元素的集合A,选取r个元素,可重排列的选择总数有**$n^r $**

1.2.理解

可重排列顾名思义,从大集合中选择的时候可以重复选取,然后再进行排列。

1.3.例题

输入的字母,输出所有的可重排序方式(每个字母可以重复)

示例

input:['a','b']
output:aa ab bb ba

代码

#include<iostream>
#include<vector>
using namespace std;
vector<char> res(3);//排列结果
//深度优先搜索方法进行可重排列
void dfs(const vector<char>& chars,int i) 
	if (i == chars.size()) 
		//打印输出chars
		for (char c : res) 
			cout << c;
		
		cout << endl;
		return;
	
	for (char c : chars) 
		res[i] = c;
		dfs(chars,i + 1);
	

void permutation(vector<char>& chars) 
	dfs(chars,0);
;
int main() 
	vector<char> chars 'a','b','c' ;//待排列的字母
	permutation(chars);
	return 0;

运行结果

2. r-可重组合

2.1.定义

n个不同元素的集合A,每个元素都可以重复选取,然后进行组合。

例:从包含1美元、2美元、5美元、10美元、20美元、 50美元及100美元的钱袋中选5张纸币,有多少种方式?假定不管纸币被选的次序,同币值的纸币不加区别,且至少每种纸币有5张。

解:7种纸币相当于7个房间,将5张纸币放入7个房间中,每个房间最多5张纸币。可以抽象成6个隔板(7个房间相当于6个隔板)与5张纸币进行组合。

C ( 5 + 7 − 1 , 5 ) = 11 ! / 6 ! 5 ! C(5+7-1,5)=11!/6!5! C(5+71,5)=11!/6!5!

2.2.理解

可重组合表示从不同类别中选取,每个类别可以重复选取。用隔板法来比较好理解。

3. n-限重排列

3.1.定义

n个元素进行全排列,但是要去除相同元素的顺序问题。

例 SUCCESS中有7个字符,4个不同的字符,S重数为3,C重数为2,E重数为1,U重数为1,它的7-限重排列数是多少?

C ( 7 , 3 ) C ( 4 , 2 ) C ( 2 , 1 ) C ( 1 , 1 ) = 7 ! / ( 3 ! 2 ! 1 ! 1 ! ) C(7,3)C(4,2)C(2,1) C(1,1)=7!/(3!2!1!1!) C(7,3)C(4,2)C(2,1)C(1,1)=7!/(3!2!1!1!)

3.2.理解

限重排列就是在全排列的基础上去除部分元素的顺序问题。注意和可重排列区分,可重排列是每个元素都可以重复,并且要考虑顺序。

4. r循环排列

4.1.定义

n个元素进行全排列,但是要形成一个首尾相连的环。

n个元素的集合A的r循环排列数为P(n,r)/r

4.2.理解

为什么要除以r因为形成环之后,第一位不会对排列数做贡献,参与排列每个元素都可以做第一个,所以要除以r.

四、代码生成排列和组合

1.排列

1.1可重排列(见三 1.3.例题 )

1.2全排列

代码

class Permutation

public:
	Permutation(string base):base(base) 
	
	void printPermutation(int index=0) 
		if (index == base.length()) 
			cout << base << endl;
		
		//每个位置都轮流选以index为起点的字母(保证了每个字母只选一次)
		for (int i = index; i < base.length(); i++)
		
			//正在安排字符串的位置 交换为i位置的字符
			if (i != index) 
				swap(base[i],base[index]);
			
			printPermutation(index + 1);//去安排字符串下一个位置的字母
			//还原交换的字母,便于下次排列
			if (i != index) 
				swap(base[i], base[index]);
			
		
	
private:
	string base;//待排序的字母
	
;

运行结果

2.组合

待续…

以上是关于离散:常用排列组合模型归纳,DFS代码实现的主要内容,如果未能解决你的问题,请参考以下文章

itertools 排列组合

DFS+剪枝Aw842.排列数 & Aw843.N-皇后问题

全排列,全组合(dfs)

用DFS 解决全排列问题的思想详解

关于各种排列组合java算法实现方法

Codeforces 991E. Bus Number (DFS+排列组合)