回溯法:输出n的全排列
2012-07-15 20:09 by 有心故我在, 4 阅读, 0 评论,收藏, 编辑1. 问题描述: 输出自然数1到n的所有不重复的排列,即n的全排列。
2. 问题分析:
(1) 解空间: n的全排列是一组n元一维向量(x1, x2, x3, ... , xn),搜索空间是:1<=xi<=n i=1,2,3,...,n
(2) 约束条件: xi互不相同。技巧:采用"数组记录状态信息", 设置n个元素的一维数组d,其中的n个元素用来记录数据1-n的使用情况,已经使用置0,未使用置1
#include<iostream> #include<memory> using namespace std; int count=0;//解个数 int n;//输入数据 int *a ;//解向量 int *d ;//解状态 void clear( ) { for(int i=1;i<=n+1;i++) { d[i]=0; } } void output()//第0个不存 { for(int i=1;i<=n;i++) cout<<a[i]<<ends; cout<<endl; } void tryArrangement(int k) { for(int i=1;i<=n;i++) { if(d[i]==0) { a[k]=i; d[i]=1; } else { //表明已用过 continue; } if(k<n) //没搜索到底 { tryArrangement(k+1); } else { count++; output(); } d[a[k]]=0; //回溯 } } int main() { cin>>n; a=new int[n+5];//解向量 d=new int[n+5];//解状态 clear( ); tryArrangement(1); }
最开始是这样置d[ ]为0的:
memset(d,0,sizeof(d));
不行,为什么?
记住,memset是按字节赋值的,第3个参数指定要赋值的字节的大小,应该改成:
memset(d,0,sizeof(int)*n);
算法说明:k为当前处理的第k个元素。上面的复杂度为O(n^n),不是一个好的算法,因此不可能用它去搜索排序树。
调试分析
k=1 if(d[1]==0) true a[1]=1; d[1]=1 try(2)
k=2 if(d[2]==0) a[2]=2 d[2]=1 try(3)
k=3 if(d[3]==0) a[3]=3; d[3]=1;
3==n; count=1; output 1 2 3
d[3]=0;
} 跳到for( )处运行 F11运行都函数末尾,
F11又跳到try(3) k=2 d[a[2]]=0
} 跳到For处运行
if(d[3]==0) a[2]=3 d[3]=1;
if(k<3) try(3)
另一种解法==也是搜索排列树的算法框架。
设计:根据全排列的概念,定义数组初始值为(1,2,3,4,。。n),这是全排列的一种结果,然后通过数据间的交换,则可产生所有不同的排列:
#include<iostream> using namespace std; int a[100],n,s=0; void output() { for(int j=1;j<=n;j++) cout<<a[j]<<ends; cout<<endl; } void tryArrange(int k) { int j; if(k>n) { output(); } else for(j=k;j<=n;j++) { swap(k,j); tryArrange(k+1); swap(k,j); //回溯时,恢复原来的排列 } } int main() { int i; cin>>n; for(i=1;i<=n;i++) a[i]=i; tryArrange(1); cout<<"换行符"<<"s="<<s; }
注意c++try是关键字。swap在ios文件中。