排列组合算法

本文介绍了使用递归思想实现排列和组合算法。对于排列,通过遍历并递归处理数组,利用原始数组长度减去当前待处理数组长度确定元素索引。组合算法则需要排除顺序要求,通过设定元素顺序保证无重复。文中提供了实现代码,并展示了测试结果,包括4的阶乘、从5个数中取2个的排列(A(5,2))以及从5个数中取3个的组合(C(5,3))。" 134772254,783471,华为OD机试C&D卷:异国客人幸运数字计算,"['华为od', '开发语言', '算法']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

排列组合算法

排列算法:

排列算法采用递归思想很简单。如1,2,3,4我们求其排列。

首先遍历1,2,3,4.

遍历1,剩下2,3,4递归处理

遍历2,剩下1,3,4递归处理

遍历3,剩下1,2,4递归处理

遍历4,剩下1,2,3递归处理

我们的目标是把相应的排列给答应出来,所以这个时候需要一个数组来保存已经处理的数字。但是关于数组的下标在递归的时候是个问题,我们改采取怎样的方式呢?可以发现这里有一个技巧,用原始数组的长度减去当前待处理的数组的长度就得到元素的数组索引。如刚开时候是1,2,3,4。数组长度等于原始数组长度,所以1的索引是0。处理1之后,剩下2,3,4,此时数组长度是3,所以我们把2的数组索引定义为4-3=1。以此类推,直到数组的长度为1。

组合算法:

组合的思想和排列一样,只不过组合之间的元素不需要前后前后顺序要求,所以我们需要排除在排列中重复的元素。关于去除的思想,我们在这里可以采取一种简单的方法,我们将组合的元素按顺序排列,保证后面的元素大于前面的元素,这样就可以实现无重复了。

如,我们这样处理:

1,2;

1,3;

1,4;

2,3;

2,4;

3,4;

这样按照从小到大的顺序从而实现了无重复的排列。

关于组合,稍微麻烦的是在处理数组的元素下标,想了好久想到到了一个比较拙劣的办法,实属本人不才。我在函数的参数列表中加了一个参数k,来表示数组元素下标。当采用递归的时候,说明要产生下一个数组元素,所以k++,递归调用完毕后,我们要依次遍历后面的元素,所以要k--。

实现代码:

一个三个函数按照顺序分别表示的是:,,的算法。

#include<iostream>
#include<list>
#include<vector>
using namespace std;
void arrangeN(list<int> &Lis,vector<int> &Vec);
void arrangeK(list<int> &Lis,vector<int> &Vec,int nK,int nN);
void combineK(list<int> &Lis,vector<int> &Vec,int nK,int nN,int k);
void main()
{
	int n1 = 10;
	list<int> Arra;
	vector<int> Vec(n1);
	
	//for(int i=1;i<=n;i++)
	//	Arra.push_back(i);
	//arrangeN(Arra,Vec);
	int n2 = 5;
	int nk = 4;
	for(int i=1;i<=n2;i++)
		Arra.push_back(i);
	//arrangeK(Arra,Vec,n2,n2);
	combineK(Arra,Vec,nk,n2,0);
}

void arrangeN(list<int> &Lis,vector<int> &Vec)
{
	list<int>::iterator iter;
	int nSize = Lis.size();
	int nLength = Vec.size();
	for(iter = Lis.begin();iter != Lis.end();iter++)
	{
		Vec[nLength-nSize] = *iter;
		if(nSize == 1)
		{
			for(int i=0;i<nLength;i++)
				cout<<Vec[i]<<"  ";
			cout<<endl;
		}
		list<int> Lisc(Lis);
		Lisc.remove(*iter);
		arrangeN(Lisc,Vec);
		
	}
}

void arrangeK(list<int> &Lis,vector<int> &Vec,int nK,int nN)
{
	list<int>::iterator iter;
	int nSize = Lis.size();

	for(iter = Lis.begin();iter != Lis.end();iter++)
	{
		Vec[nN-nSize] = *iter;
		if(nN-nSize +1 == nK)
		{
			for(int i=0;i<nK;i++)
				cout<<Vec[i]<<"  ";
			cout<<endl;
		}
		list<int> Lisc(Lis);
		Lisc.remove(*iter);
		arrangeK(Lisc,Vec,nK,nN);	
	}
}

void combineK(list<int> &Lis,vector<int> &Vec,int nK,int nN,int k)
{
	int nSize = Lis.size();
	list<int>::iterator iter;
	for(iter = Lis.begin();iter != Lis.end();iter++)
	{
		if(nN - nSize == 0)
			k = 0;
		Vec[k] = *iter;
		if( k + 1 == nK)
		{
			for(int j=0;j<nK;j++)
				cout<<Vec[j]<<"  ";
			cout<<endl;
		}
		else
		{
			list<int> Lisc( ++iter,Lis.end() );
			iter--;
			k++;
			combineK(Lisc,Vec,nK,nN,k);
			k--;
		}
	} 
}

测试结果:

4!

A(5,2)


C(5,3)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值