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

本文详细介绍了排列、组合的概念及其计算公式,并通过实例解析了可重排列和可重组合的差异。同时,给出了n-限重排列和r循环排列的定义。文中还提供了C++代码实现全排列和可重排列,帮助读者理解这些概念并能够实际应用。
摘要由CSDN通过智能技术生成

一、排列

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张纸币进行组合。问题转换为6个隔板和5张纸币混合在一起,将其同等看待,一共有11种选择,随机选择其中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.组合

待续…

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值