一、题目:编写一个输出1,2,3…,n,n个数字所组成的所有排列.
二、分析题意:
第一步,先思考一些例子。
例如:n=3 ,则全排列为:
111 112 113 -> 121 122 123 -> 131 132 133211 212 213 -> 221 222 223 -> 231 232 233
311 312 313 -> 321 222 223 -> 331 332 333
第二步,分步思考,若仅输出111、112、113:
很容易想到这样:
t=1; a[t]=0;
do{
a[t]=a[t]+1;
if(t==3) // 找到一种排列,则输出
输出a[1],a[2],a[3]
else
{ ++t; a[t]=0; } //继续向前搜索
}while(a[3]!=3);
第三步,思考如何从 113 过渡到 121?
想到:从113 ->114 当最后一位超过最大数字时,无效。下组数字的最后位要“归零”,同时回溯到前一位“进位”。
发现规律:
(1)每组数中当第t位超过最大值时,下组数的此位要“归零”,同时回溯到 t-1 位“进位”,由此前进,回溯,再前进。
(2)由此,直到回溯到第 t=0 位结束。
三、源代码:
编写一个输出1,2,3…,n,n个数字所组成的所有排列.
//编写一个输出1,2,3…,n,n个数字所组成的所有排列.
#include<iostream>
#define N 10
using namespace std;
int main(){
int t=1;
int n;//n为给出的一串数中的最大数
cin>>n;
int m;//m为给出的位数
cin>>m;
int a[N];
a[t]=0;
do{
a[t]=a[t]+1;
if(a[t]>n){//超过最大值,回溯
a[t]=0;
t--;
}else{
if(t==m){//已到最后一位,找到一种排列,则输出
for(int i=1;i<=m;i++)
cout<<a[i]<<" ";
cout<<endl;
}else{//继续向前搜索
t++;
a[t]=0;
}
}
}while(t!=0);//do..while的意思是当满足括号里面的条件时,一直执行函数体,最后还有个;
return 0;
}
//下面是迭代回溯的方法,思路及步骤直接在代码上注释了!
#include<iostream>
#define N 10
#include<cstring>
using namespace std;
int a[N];
int t=1;
int n;//n为给出的一串数中的最大数
int m;//m为给出的位数
//常用的非递归迭代过程
void Iter_backtrack(){
//第一步,先把每个数组都初始化为0
memset(a,0,sizeof(a));
//第二步,非递归迭代过程
t=1;
while(t!=0){//1.先想到回溯的条件,当回溯到第0位结束
//2.再想什么时候回溯,什么时候继续前进
if(a[t]<n){//这种情况下不回溯
a[t]=a[t]+1;
if(a[t]<=n){
if(t==m){
for(int i=1;i<=m;i++)
cout<<a[i]<<" ";
cout<<endl;
}else t++;
}
}else{//这种情况下回溯
a[t]=0;//这个与上面那个回溯规律是一样的
t--;
}
}
}
int main(){
cin>>n;
cin>>m;
Iter_backtrack();
return 0;
}