请编写程序输出前n个正整数的全排列(n<10),并通过9个测试用例(即n从1到9)观察n逐步增大时程序的运行时间。
输入格式:
输入给出正整数n(<10)。
输出格式:
输出1到n的全排列。每种排列占一行,数字间无空格。排列的输出顺序为字典序,即序列a1 ,a2,⋯,an 排在序列b1,b2 ,⋯,bn之前,如果存在k使得a1 =b1 ⋯,a
k=bk并且 ak+1<bk+1。
输入样例:
3
输出样例:
123
132
213
231
312
321
方法一:(回溯)
//思路:借鉴第一题,将全排列抽象成一个数(n个数的和)的分解,加上判断函数剪去不必要的部分即可
#include<stdio.h>
int m;
int cnt=0;
int zz[35];
void print()
{
int i;
for(i=0;i<m;i++)
{
printf("%d",zz[i]);
}
}
int check(int i,int l)
{
int n;
int w;
for(w=0;w<l;w++)
{
if(zz[w]==i)
return 0;
}
return 1;
}
int F(int n,int k,int l)
{
int i;
if(n==0)
{
print();
printf("\n");
return 0;
}
for(i=1;i<=m;i++)
{
if(check(i,l))
{
zz[l]=i;
F(n-i,i,l+1);
}
}
}
int add(int n)
{
int i;
int sum=0;
for(i=0;i<=n;i++)
{
sum+=i;
}
return sum;
}
int main()
{
int n;
int sum;
scanf("%d",&n);
sum=add(n);
m=n;
F(sum,0,0);
return 0;
}
方法二:
//思路:采用递归思想,将问题分解,每次移动都会固定一些数字是不动的,如123,132... 其中 1 就是不动的那个数。
//每个小问题的解决通过将数组元素“拿”到离他最近的不动的元素之后,即将其取出,目标位置及以后的数后移,将拿出来的数填充上
//复原方法相反
#include <iostream>
#include <stdio.h>
using namespace std;
void Print(int *a,int t);
void Insert(int* &a,int t,int f) //将t位置的数拿到f处,f处及以后向后移
{
int i;
int temp;
temp=*(a+t);
for(i=t;i>f;i--)
{
*(a+i)=*(a+i-1);
}
*(a+f)=temp;
}
void Move(int* &a,int t,int f) //将上面那个函数的改变还原
{
int i;
int temp=a[t];
for(i=t;i<f;i++)
{
a[i]=a[i+1];
}
a[f]=temp;
}
void swap(int &a,int &b){
int temp=a;
a=b;
b=temp;
}
void Print(int* a,int low) //输出函数独立出来,没别的,主要方便调试
{
for(int i=0;i<=low;i++)
cout<<a[i];
cout<<endl;
}
void perm(int a[],int low,int high){
if(low==high){ //当low==high时,此时list就是其中一个排列,输出list
Print(a,low);
}else{
for(int i=low;i<=high;i++){ //每个元素插入到最近的一个不动的数字后
Insert(a,i,low); //将元素插入,
perm(a,low+1,high); //交换后,得到子序列,用函数perm得到子序列的全排列
Move(a,low,i); //将数组还原到上一个改变之前
}
}
}
int main()
{int n;
scanf("%d",&n);
int *a;
a=new int[20]; //为了以后数组够用,不会出现溢出现象,特意将数组开大
for(int i=0;i<n;i++)
{
a[i]=i+1;
}
perm(a,0,n-1);
return 0;
}