ACM学习历程21——各种排列组合问题

原创 2016年08月28日 20:19:55

在这篇博文中,介绍关于1—N和整型数组的排列算法,这些算法的主要用到了递归的思想,即在函数或子过程的内部直接或者间接调用自己的算法。递归算法解决问题的特点在于:递归本身就是在子过程或者函数里调用自身;在使用递归策略时,必须有一个明确的递归结束条件,也就是不存在死递归。当然递归的缺点也是明显的,递归算法虽然间接但是算法求解的运行效率较低。同时在递归调用的过程中系统为每一层的返回点、局部变量等开辟了栈,因而递归次数过多造成栈的溢出。虽然递归算法在效率和内存等方面存在缺点,但是递归算法形式简单易于理解,因此也是必须掌握的一种编程技巧。下面将以各种排列组合算法题目,介绍递归算法的应用。

一、生成1—N的排列:输入一个整数N,然后对1,2,3......N进行全排列,输出排列的情况

#include<iostream>
using namespace std;

//记录总数
int total=0;

void printPermutation(int n,int *array,int cur)
{
	int i,j;
	if(cur==n)
	{
		total++;
		for(i=0;i<n;i++)
			cout<<array[i]<<" ";
		cout<<endl;
	}
	else
	{
		for(i=1;i<=n;i++)
		{
			int flag=1;
			//判断i是否已经被选过
			for(j=0;j<cur;j++)
				if(array[j]==i)
				{
					flag=0;
					break;
				}
			//i没有被选过放入cur位置
			if(flag)
			{
				array[cur]=i;
				printPermutation(n,array,cur+1);
			}
		}
	}
}

int main()
{
	int n,array[10];
	cout<<"N=";
	cin>>n;
	printPermutation(n,array,0);
	cout<<"total="<<total<<endl;
	return 0;
}
二、使用next_permutation函数对数组中的元素进行全排列
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;

int main()
{
	int i,n,p[20];
	int count=0;
	cout<<"n=";
	cin>>n;
	for(i=0;i<n;i++)
		cin>>p[i];
	sort(p,p+n);
	do
	{
		count++;
		for(i=0;i<n;i++)
			cout<<p[i]<<" ";
		cout<<endl;
	}
	while(next_permutation(p,p+n));
	cout<<"count="<<count<<endl;
	return 0;
}
三、数组中元素的排列组合:要求数组中不能出现重复元素

#include<iostream>
#include<cstdio>
using namespace std;
int count=0;

void printPermutation(int n,int *arr,int *A,int cur)
{
	int i,j;
	if(cur==n)//递归边界
	{
		count++;
		for(i=0;i<n;i++)
			printf("%d ",A[i]);
		printf("\n");
	}
	else
		for(i=0;i<n;i++)//在A[i]中填各种数i
		{
			int ok=1;
			for(j=0;j<cur;j++)
				if(A[j]==arr[i])
				{
					ok=0;//如果i已经在A[0]~A[cur-1]出现过,则不能再选
					break;
				}

				if(ok)
				{
					A[cur]=arr[i];
					printPermutation(n,arr,A,cur+1);
				}
		}
}

int main()
{
	int array[100],arr[100];
	int i,n;
	cout<<"n=";
	cin>>n;
	for(i=0;i<n;i++)
		cin>>arr[i];
	printPermutation(n,arr,array,0);
	printf("count=%d\n",count);
	return 0;
}

需要注意的是这种方法要求数组中的元素不能重复,原因在于若数组中存在重复的元素,那么当程序执行到A[j]==arr[i]时,标志变量ok的值一直为0,所以cur+1的操作将不会发生,直到外层循环for(i=0;i<n;i++)结束整个递归函数就结束了。

四、数组的排列组合:允许数组中出现重复的元素

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;

int total=0;

void printPermutation(int n,int *arr,int *array,int cur)
{
	int i,j;
	if(cur==n)
	{
		total++;
		for(i=0;i<n;i++)
			cout<<array[i]<<" ";
		cout<<endl;
	}
	else
	{	
		for(i=0;i<n;i++)
		{
			if(!i || arr[i]!=arr[i-1])
			{
				int c1=0,c2=0;
				//arr[i]被填的个数
				for(j=0;j<cur;j++)
					if(array[j]==arr[i])
						c1++;
				//array中arr[i]的个数
				for(j=0;j<n;j++)
					if(arr[j]==arr[i])
						c2++;
				if(c1<c2)
				{
					array[cur]=arr[i];
					printPermutation(n,arr,array,cur+1);
				}
			}
		}
	}
}

int main()
{
	int array[100];
	int arr[100],n,i;
	cout<<"n=";
	cin>>n;
	for(i=0;i<n;i++)
		cin>>arr[i];
	sort(arr,arr+n);
	printPermutation(n,arr,array,0);
	printf("total=%d\n",total);
	return 0;
}
注:上面数组中的元素可以重复,但是在调用递归函数之前要对该数组排序。

五、数组的排列组合:选取其中的几个数进行排列组合,允许数组中存在重复的元素

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;
int total=0;

void printPermutation(int m,int n,int *arr,int *array,int cur)
{
	int i,j;
	if(cur==m)//递归边界
	{
		total++;
		for(i=0;i<m;i++)
			printf("%d ",array[i]);
		printf("\n");
	}
	else
		for(i=0;i<n;i++)//在array中填各种数i
		{
			if(!i||arr[i]!=arr[i-1])
			{
				int c1=0,c2=0;
				for(j=0;j<cur;j++)
					if(array[j]==arr[i])
						c1++;
				for(j=0;j<n;j++)
					if(arr[i]==arr[j])
						c2++;
				if(c1<c2)
				{
					array[cur]=arr[i];
					printPermutation(m,n,arr,array,cur+1);
				}
			}
		}
}

int main()
{
	int array[100];
	int arr[50];
	int i,n;
	cout<<"n=";
	cin>>n;
	for(i=0;i<n;i++)
		cin>>arr[i];
	sort(arr,arr+n);
	printPermutation(3,n,arr,array,0);
	printf("total=%d\n",total);
	return 0;
}
版权声明:本文为博主原创文章,转载注明出处!

ACM-排列组合

话说排列组合博大精深,看来确实是的,我完全驾驭不了那些公式、定理啊! 哎,算了,骨头难啃就只有慢慢啃了。那今天就先来点简单的,先搞搞组合数吧! 组合,简单的说就是从n个东西里面,挑出k个来,有多少种挑...
  • u011787119
  • u011787119
  • 2014年10月05日 08:47
  • 749

HDU-计算机学院大学生程序设计竞赛(2015’11)1005 ACM组队安排(排列组合)

n个人中有i个人一人一组,2*j个人两人一组,3*k个人三人一组(i+2*j+3*k=n),枚举i,j,k,用排列组合公式直接算结果即可 幸亏还记得点高中数学:无序地将mn分成m等份=[C(mn,2)...
  • idealism_xxm
  • idealism_xxm
  • 2015年11月29日 18:26
  • 959

关于acm中常见的计算组合数的方法总结

关于acm中常见的计算组合数的方法总结
  • u012476429
  • u012476429
  • 2014年02月27日 20:28
  • 4565

[ACM] poj 2249 Binomial Showdown (排列组合公式优化)

Description In how many ways can you choose k elements out of n elements, not taking order into acc...
  • sr19930829
  • sr19930829
  • 2014年04月05日 20:02
  • 1701

ACM~排列组合&&hdu样例

排列组合是数学中的一个分支,在计算机编程方面也有很多的应用,主要有排列公式和组合公式,错排公式、母函数、Catalan Number(卡特兰数)等。 一、有关组合数学的公式 1、排列公式   ...
  • u012435889
  • u012435889
  • 2014年10月28日 12:42
  • 1853

ACM常见组合博弈游戏

这两天认识了几个组合游戏的基础模型,希望自己能更新下去。。Ferguson游戏Description Initial 有两个盒子,一个装有 m 颗糖,一个装有 n 颗糖,表示为 (m, n) . St...
  • qq_15714857
  • qq_15714857
  • 2015年11月07日 00:03
  • 1761

ACM组合数学题目列表

转自:http://www.cnblogs.com/hebozi/archive/2012/08/06/2624623.html 基本组合计数 HDU 1028 Ignatius a...
  • cqlf__
  • cqlf__
  • 2012年08月26日 10:48
  • 2239

面试题:对1、2、2、3、4、5六个数字进行排列组合

Sorry,到现在还没完全进入写代码的状态,头晕晕的。。。上午看到一同学发了一道排列组合的编程笔试题,感觉挺有意思的,反正都没进入状态,就先试下,看能否解决,并进入状态。题目:用1、2、2、3、4、5...
  • a10615
  • a10615
  • 2016年04月11日 18:52
  • 4376

border-collapse:collapse; 表格边框合并属性

 border-collapse:collapse;  表格边框合并属性
  • wuhen8
  • wuhen8
  • 2011年04月06日 11:22
  • 210

环状序列

长度为n的换证串有n种表示法,分别为从某个位置开始顺时针得到。例如图: 有10种表示:CGAGTCAGCT,GAGTCAGCTC,AGTCAGCTCG等。在这些表示法中,字典序最小的成为“最小表示”...
  • xilihong816
  • xilihong816
  • 2015年08月23日 16:54
  • 1115
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:ACM学习历程21——各种排列组合问题
举报原因:
原因补充:

(最多只允许输入30个字)