全排列算法

31 篇文章 0 订阅

所谓全排列算法,就是输入n个数据,然后输出该n个数据的所有的排列情况。

1.每个元素不相同情况下的排列。

排列的用计算机程序的思路来考虑就是递归地往数组A里添加元素的过程,如果放完了元素就输出并回溯。为了形象说明情况,我们举个例子,并给出算法的流程图和程序实现。

demo:输入n,输出1~n的全排列。

流程图:


程序实现:

#include<iostream>
using namespace std;
const int maxn = 10000 + 5;
int A[maxn];
int cur,T;
void show(int* A,int cur)
{
	if (cur >= T){
		for (int i = 0; i < T; i++){
			cout << A[i];
		}
		cout << endl;
	}
	else{
		for (int i = 1; i <=T; i++){
			bool ok = true;
			for (int j = 0; j < cur;j++)
			if (A[j] == i)ok = false;
			if (ok){
				A[cur] = i;
				show(A, cur + 1);
			}
		}
	}
}
int main()
{
	cin >> T;
	show(A,0);
	system("pause");
	return 0;
}
程序运行及及结果:


2.含有相同元素的全排列

1中之所以能根据A中有无元素v来决定放不放入v,是因为输入的元素是相同的。但如果输入的元素含有相同的元素,那么相同的元素就只能放进去一个,问题就出现在是A中虽然已经有元素v了,但输入的元素并没有放完。解决的办法是统计A中元素v出现的次数,如果小于输入元素中v的个数,那么就可以放。对应的算法流程图和程序实现如下。

流程图:


程序实现:

#include<iostream>
using namespace std;
const int maxn = 10000 + 5;
int A[maxn],S[maxn];
int cur,T;
void show(int* A,int cur)
{
	if (cur >= T){
		for (int i = 0; i < T; i++){
			cout << A[i];
		}
		cout << endl;
	}
	else{
		for (int i = 0; i <T; i++){
			int cntA = 0;
			int cntS = 0;
			for (int j = 0; j < cur;j++)
			if (A[j] == S[i])cntA++;
			for (int j = 0; j < T;j++)
			if (S[j] == S[i])cntS++;
			if (cntA<cntS){
				A[cur] = S[i];
				show(A, cur + 1);
			}
		}
	}
}
int main()
{
	cin >> T;
	for (int i = 0; i < T; i++)
		cin >> S[i];
	show(A,0);
	system("pause");
	return 0;
}
然而,上面的程序当输入

3

1 1 1

的时候,输出的是27个111。很明显答案错了,正确的应该是只输出一个111就好。出现这种错误是因为递归的每一层栈中都三个1都是可以放进A的。比如说第一次调用,先试着把第1个1作为开头,递归调用结束后再尝试用第2个1作为开头,递归调用结束后再尝试用第3个1作为开头,再次递归调用。然而,实际上这3个1都是相同的,应该只递归1次而不是3次。

换句话说,我们枚举的下标i应不重复、不遗漏地取遍所有S[i]值.所以只需检查S的第一个元素和所有“与前面不同”的元素。

由于S数组已经排过序,所以只需检查S的第一个元素和所有“与前一个元素不相同”的元素,即只需在“for(int =0;i<n;i++)”和其后的花括号之前加“if(!i||S[i]!=S[i-1])”即可。代码如下:

#include<iostream>
using namespace std;
const int maxn = 10000 + 5;
int A[maxn],S[maxn];
int cur,T;
void show(int* A,int cur)
{
	if (cur >= T){
		for (int i = 0; i < T; i++){
			cout << A[i];
		}
		cout << endl;
	}
	else{
		for (int i = 0; i <T; i++)
		if (!i || S[i] != S[i - 1]){
			int cntA = 0;
			int cntS = 0;
			for (int j = 0; j < cur; j++)
			if (A[j] == S[i])cntA++;
			for (int j = 0; j < T; j++)
			if (S[j] == S[i])cntS++;
			if (cntA < cntS){
				A[cur] = S[i];
				show(A, cur + 1);
			}
		}
	}
}
int main()
{
	cin >> T;
	for (int i = 0; i < T; i++)
		cin >> S[i];
	show(A,0);
	system("pause");
	return 0;
}

假如S中的元素不是排好序的,只需检查S的第一个元素和“与S[0]~S[i-1]”都不重复的元素。程序实现如下:

#include<iostream>
using namespace std;
const int maxn = 10000 + 5;
int A[maxn],S[maxn];
int cur,T;
void show(int* A,int cur)
{
	if (cur >= T){
		for (int i = 0; i < T; i++){
			cout << A[i];
		}
		cout << endl;
	}
	else{
		for (int i = 0; i <T; i++){
			int cntA = 0;
			int cntS = 0;
			bool nohaved = true;
			for (int j = 0; j < cur; j++)
			if (A[j] == S[i])cntA++;
			for (int j = 0; j < T; j++)
			if (S[j] == S[i])cntS++;
			for (int j = 0; j < i;j++)
			if (S[j] == S[i])nohaved = false;
			if (!i || nohaved){
				if (cntA < cntS){
					A[cur] = S[i];
					show(A, cur + 1);
				}
			}
		}
	}
}
int main()
{
	cin >> T;
	for (int i = 0; i < T; i++)
		cin >> S[i];
	show(A,0);
	system("pause");
	return 0;
}

3.next_permutation实现全排列

上面讲的都是通过递归调用来实现全排列的,在C++的头文件中已经有现成生成下一个全排列的程序,只需迭代调用即可。程序实现如下:

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=10000+5;
int P[maxn];
int main()
{
	int T;
	cin >> T;
	for (int i = 0; i < T; i++)cin >> P[i];
	sort(P, P+T);
	do{
		for (int i = 0; i < T; i++)cout << P[i];
		cout << endl;
	} while (next_permutation(P, P + T));
	system("pause");
	return 0;
}
使用该方法比较直观,但是运行效率肯定不高。


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值