全排列问题(可重复排列和不可重复排列)

版权声明:未经本人同意,禁止转载。 https://blog.csdn.net/qq_34022601/article/details/85331232

全排列

1. 不可重复全排列

全排列问题一般要求按照字典顺序排列出来.

例如:

1 2 3     1 3 2

2 1 3     2 3 1

3 1 2     3 2 1

全排列问题一般尝试用递归的方式去做,用 for 循环来解决字典序的问题.

#include <cstdio>
using namespace std;
const int N=1024;
int vis[N];
int A[N];
void print_permutation(int n,int cur)
{
	if (cur==n)			//cur==n 表示已经得到一组排列,输出 
	{
		for (int i=0;i<n;i++)
			printf ("%d ",A[i]);
		printf ("\n");
		return ; 
	}
	for (int i=1;i<=n;i++)//for 循环中依次增大,保证了字典序
	{
		if (vis[i]==0)//当元素 i 没有出现,则加入当前 A 中 
		{
			A[cur++]=i;
			vis[i]=1;
			print_permutation(n,cur);
			cur--;		//注意恢复变量,这样在下一层的排列中,元素 i 可以被选中 
			vis[i]=0;
		}
	}
}
int main()
{
	int n;
	scanf ("%d",&n);
	print_permutation(n,0);
	return 0;
} 

2. 可重复全排列

之前的代码只能保证1-n的全排列,但是待排列元素不是1~n,比如是 1 1 2 的排列

排列如下:

1 1 2

1 2 1

2 1 1

新的要求下,我们要对代码进行小小的改动。

设置读入数组P[N],读入可重复元素序列,统计每个元素出现的次数;

在递归的时候,我们只需要检查某元素在A数组中出现次数和P数组中次数是否相等即可。若不相等,可以继续添加,否则不能继续添加。

除了这个之外,我们还应该考虑重复枚举的状况。

例如:1 1 1 2

在排列中多次枚举中重复出现

1 1 1 2、1 1 1 2 或者 1 2 1 1 、 1 2 1 1 等其他情况。

我们只需要保证同一层递归中,当前添加的元素和上一次添加的元素不同即可。

代码如下:

#include <cstdio>
#include <algorithm> 
using namespace std;
const int N=1024;
int A[N];
int P[N]; 
int vis_A[N],vis_P[N]; //这里注意数组范围应与实际元素范围匹配
void print_permutation_repitition(int n,int cur)
{
	if (cur==n)
	{
		for (int i=0;i<n;i++)
			printf ("%d ",A[i]);
		printf ("\n");
		return ; 
	}
	int last=-111; 
	for (int i=1;i<=n;i++)
	{
		if (vis_P[P[i]]!=vis_A[P[i]]&&P[i]!=last)//判断出现次数是否相等 && 是否和前一个枚举的元素相等. 
		{
			last=P[i];
			A[cur++]=P[i];
			vis_A[P[i]]++;
			print_permutation_repitition(n,cur);
			cur--;
			vis_A[P[i]]--;
		}
	}
}
int main()
{
	int n;
	scanf ("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf ("%d",&P[i]);
		vis_P[P[i]]++;	//统计次数 
	}
    sort(P+1,P+n+1);//排序一下,保证字典序
	print_permutation_repitition(n,0);
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_34022601/article/details/85331232