下面讨论的是n个互不相同的数形成的不同排列的个数。
毕竟,假如n个数当中有相同的数,那n!种排列当中肯定会有一些排列是重复的,这样就是一个不一样的问题了。
/*===================================== 数的全排列问题。将n个数字1,2,…n的所有排列枚举出来。 2 3 1 2 1 3 3 1 2 3 2 1 思路: 递归函数定义如下: void fun(int a[],int flag[],int i,int ans[]); //原始数据存放于a[]。flag[]的每一个元素标记a[]对应位置处的元素是否已经被选用。 //i表示当前对某排列而言,正在寻找到第i个数据。 //ans[]是存放每一个排列的地方。每当放够n个元素到ans则开始打印该数组。 程序中先把原始数据读入到数组a[]。flag[]数组元素全部置0. 生成一个排列的过程可以这样认为: 每次递归都扫描flag[],寻找一个flag[i]==0然后把a[i]选到排列当中。 (也即放到ans[i]当中。选a[i]后要把flag[i]置1.) 这样就确定了当前排列的第i个元素。 然后递归进入下一层确定第i+1个数。 以此类推,逐层递归直至i==n-1(因为i从0开始,所以是i==n-1)就认为已经得到了一个 完整的排列。这个时候可以把ans数组输出了。 输出后可以开始回溯了。 每次回溯都要把flag[i]置0以便还原现场。(相当于ans[i]不选a[i]了。) 置0后继续循环枚举当前位置的其他可能取值。 ======================================*/
下面是我自己按照自己的理解做的,其实有点浪费空间了:
1 #include<stdio.h> 2 int n,count;//n表示参与排列的数据的个数,count表示不同排列的个数 3 void fun(int a[],int flag[],int i,int ans[]); 4 //原始数据存放于a[]。flag[]的每一个元素标记a[]对应位置处的元素是否已经被选用。 5 //i表示当前对某排列而言,正在寻找到第i个数据。 6 //ans[]是存放每一个排列的地方。每当放够n个元素到ans则开始打印该数组。 7 int main() 8 { 9 int i; 10 int a[20],flag[20],ans[20]; 11 freopen("5.out","w",stdout); 12 scanf("%d",&n); 13 for(i=0;i<n;i++) 14 { 15 flag[i]=0; 16 a[i]=i+1; 17 } 18 count=0; 19 fun(a,flag,0,ans);//从第0号开始出发,依次确定每一个位置的数值 20 printf("total:%d\n",count); 21 return 0; 22 } 23 void fun(int a[],int flag[],int i,int ans[]) 24 { 25 int j,k; 26 if(i==n-1) 27 { 28 for(j=0;j<n;j++) 29 { 30 if(flag[j]==0)//找到了一个排列,把这个排列给输出。 31 { 32 ans[i]=a[j]; 33 for(k=0;k<n;k++) printf("%d ",ans[k]); 34 printf("\n"); 35 count++; 36 return ; 37 } 38 } 39 } 40 else 41 { 42 for(j=0;j<n;j++) 43 { 44 if(flag[j]==0) 45 { 46 ans[i]=a[j]; 47 48 flag[j]=1; 49 fun(a,flag,i+1,ans); 50 flag[j]=0; 51 } 52 } 53 } 54 }