一、题目
生成1~n的全排列
二、解题思路
我们尝试用递归的思想解决:
- 1与1交换,继续求子问题(2,3,...,n)的子问题。
- 2与1交换,继续求子问题(1,3,...,n)的子问题。
- 3与1交换,继续求子问题(2,1,...,n)的子问题。
................................
- n与1交换,继续求子问题(2,3,...,1)的子问题。
这样每个数开头一次,递归求解剩下序列的排序,即可得到n个数的全排列。假如 我们有1,2,3,4,下面我们用上述思想生成1,2,3,4的全排列。
- 首先,1与1交换,在继续求子问题(2,3,4),该子问题又分为三种子问题,一种是2和2交换,继续求子问题(3,4)接下来继续求子问题(3,4),一种是3和3交换,剩下子问题{4},单独元素,直接返回排列为(1,2,3,4),另一种是4和3交换,剩下子问题{3}, 单独元素,直接返回(1,2,4,3);另一个是3和2交换,继续求(2,4)的子问题,接下来继续求子问题(2,4),一种是2和2交换,剩下子问题{4},单独元素,直接返回排列为(1,3,2,4),另一种是4和2交换,剩下子问题{2}, 单独元素,直接返回(1,3,4,2);最后一种是4和2交换,继续求(3,2)的子问题,接下来继续求子问题(3,2),一种是3和3交换,剩下子问题{2},单独元素,直接返回排列为(1,4,3,2),另一种是3和2交换,剩下子问题{2}, 单独元素,直接返回(1,4,2,3)。
- 2与1交换,继续求子问题(1,3,4)的子问题。略
- 3与1交换,继续求子问题(2,1,4)的子问题。略
- 4与1交换,继续求子问题(2,3,1)的子问题。略
三、代码编写
#include <iostream>
#define N 100
using namespace std;
//保存待排列数组
int a[N] = {0};
//记录需要排列元素个数
int length = 0;
//交换数组的两个数,参数为数组索引
void swap(int s,int t){
int temp = a[t];
a[t] = a[s];
a[s] = temp;
}
//index表示从第index开始,计算index到n的的全排列,
//即dfs(1)代表从第一数算起,生成1-n的全排列
void dfs(int index){
if(index > length){
for(int i = 1;i <= length ; i++){
cout<<a[i]<<" ";
}
cout<<endl;
return;
}
else{
for(int i = index ; i <= length ;i++){
swap(i,index);
//继续生成index+1到n的全排列
dfs(index+1);
//回溯时交换回来
swap(i,index);
}
}
}
int main()
{
cout << "请输入排列元素个数:" ;
cin>>length;
//初始化
for(int i = 1 ; i<=length ; i++){
a[i] = i;
}
//生成1到length的全排列
dfs(1);
return 0;
}
四、运行结果 及分析
此算法运用了交换的思想,但是生成排列并不是按照字典序的排序生成的,细心的读者可以注意到。如果要生成按字典序 生成的全排列请点击这里。此算法也可以解决一些问题,如旅行商问题。稍后我会更新旅行商问题,全排列算法是解决旅行商问题的算法之一。