全排列c/c++实现

题目:

给出n个字母,逐行输出所有可能的排列组合。

输入在第一行给出一个数字n,接下一行给出n个字母。

输出所有可能的排列,每种排列占一行。

案例:

输入:

3
abc

输出:

abc
acb
bac
bca
cba
cab

思路:

利用数组内部的有序交换,防止重复,这次我们直接用老板的思维来看待问题,以对ABC进行排列举例,最大老板只需要用A分别与A,B,C进行交换,这里是三种情况三条分支,用循环来控制。下一层有3个同级老板要对BC,AC,BA进行同样的操作,依此类推,详见下图:

最顶层老板思维:
        1.制定好规则,保证下一层老板的行为和所解决的问题是和自己一样的,也就是递归的形式不(递归重复部分),只是规模变小了(递归变量设计)。而规模最小自然也就是递归的截止条件了(递归截止条件)。
        2.考虑好如何才算是解决问题,这题当任务分配至最小老板,就产生了问题的其中一个解,所以为了保证同级老板的公平性,需要将解决问题的条件变回原样(也就是需要回溯!!) 。回想硬币分配问题,是每个老板汇总方法数,最大老板得到最终汇总才算解决问题,自然不用回溯。
本题难点:
1.多分支循环设计
2.回溯。 
3.理解程序的执行时是先纵后横 

上代码:

#include <bits/stdc++.h>
using namespace std;
char str[105];
int n;
int fullpermutation(int k); 
int main() {
	cin >> n;
	getchar();
	for(int i=0;i<n;i++) 
		scanf("%c",&str[i]);
	fullpermutation(0);
	return 0;
} 

int fullpermutation(int k) {
	if(k==n) {
		for(int i=0;i<k;i++)
			printf("%c",str[i]);
		printf("\n");
	}
	for(int i=k;i<n;i++) {//很多个分支,用循环! 
		swap(str[k],str[i]);//每个当前分支,当前拥有有的字母都要打一次头 
		fullpermutation(k+1);//下个老板 
		swap(str[i],str[k]);//回溯,因为上一层老板要保证分发下去什么样,收回来就得是什么样。
		/*注意和上一题硬币分配的区别,硬币那题上一层老板要得到下一层老板的方法数往上汇总,层层累加 
		这题最底层老板产生的就是其中一个答案,直接保存或输出,而上一层老板要保证分发下去什么样,
		收回来就得是什么样。以便于每个统计老板的分配都是公平的,不会出错的,也就是排序不重复。 
		*/ 
	}
}

        下面加大难度,如果题目要求按字典序排序输出,那么上述算法就无法满足了,原因是交换的思路,无法保证字母是按照字典序排序的,从画的图里也可以看出,那么这要如何解决呢?

        首先交换的方式肯定不可行了,那就只能逐个字母进行拼凑,排除重复需要额外定义一个规模为n的标记数组,每次都遍历一遍所有字母,未被标记的就可以加入拼凑行列,拼凑的长度达到n就可以输出,每次递归结束要将标记恢复。细节见代码:

#include <bits/stdc++.h>
using namespace std;
char str[105],ans[105];
int vis[105];
int n,p;
int fullpermutation(int k); 
int main() {
	cin >> n;
	getchar();
	for(int i=0;i<n;i++) 
		scanf("%c",&str[i]);
	fullpermutation(0);
	return 0;
} 

int fullpermutation(int k) {
	if(k==n) {
		for(int i=0;i<k;i++)
			printf("%c",ans[i]);
		printf("\n");
	}
	for(int i=0;i<n;i++) {
		if(!vis[i]) {
			vis[i] = 1;//标记数组 
			ans[p++] = str[i];//未被标记纳入拼凑行列 
			fullpermutation(k+1);
			p--;//恢复原状态 
			vis[i] = 0;
		}
	}
}

以上~

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值