全排列问题


求1-n的全排列并输出每种排列

在这里介绍两种全排列的思想以及实现方式

思想一:

  以1-4的全排列举例:第一个位置有4种放置的方式,分别是1,2,3,4。当第一个位置放了1之后第二个位置有3种摆放的方式,分别是2,3,4。依次类推我们不难的到一个树状结构(如下图1),第一个行代表一个数字都没有放置,第二行代表放置第一个数字的方法,第三行代表放置了他的根之后能接受的放置的方法,以此类推,从根节点到叶节点所走过的所有节点所连成的字符串就是他所代表的排列方式(如图二)。

如何用代码实现这种思想,首先想到广度优先搜索,记录每一种选择的情况,最后输出所有符合要求的排列即可,但如果记录每一种选择的情况会使代码的空间复杂度达到n*n!,这是我们不想看到的。所以采用深度优先的思想,将没一次数字的选择看成将这个数字和对应位置上的数字交换,这样就可以使空间复杂度降到n。我们用1-3的全排列举例(如图三)。

 

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>

using namespace std;
int n;
void print(const int a[]){
    for(int i=0;i<n;i++){
        printf("%d",a[i]);
    }
    printf("\n");
}

void f(int a[],int x){
    if(x==n)print(a);
    else{
        for(int i=x;i<n;i++){
            swap(a[x],a[i]);
            f(a,x+1);
            swap(a[x],a[i]);
        }
    }
}

int main()
{
    int a[10];
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        a[i]=i+1;
    }
    f(a,0);
    return 0;
}

思想二:

   假设现在有一种排列使1,2,3,4要在这个排列的基础上加一个数字会有5种排列的方式,如下图。

 

   根据这样的思想,我们成列出1-3的全排列。(如图4)

 

算法:

  现在给每个数字规定一个上标,0代表可以向左移动,1代表向右移动。如果上标所指的数字小于这个数字,那么就认为这个数字是可移动的。

  以1-3举例:初始认为所有数字的上标都是0,即10 20 30

  当存在一个数字可以移动时,我们要完成下面的事。

  (1)求出最大的可移动整数m。

  (2)交换m和他的上标所指的与他相邻的整数。

  (3)交换所有满足p>m的整数p上标改变(1变0,0变1)

因为213没有可以移动的数字,所以算法终止。

以上的算法都是不带重复的全排列组合,如果要求带重复的全排列请查看:this


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM