求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
