想不想打印所有排列?
輸入整數n,按字典序從小到大輸出前n個數的所有排列。
1 生成1~n的排列
偽代碼:
void print_permutation(序列A,集合S) { if(S為空) 輸出序列A; else按照從小到大的順序依次考慮S中的每個元素 { print_permutation(在A的末尾添加v后得到的新序列,S-{v}); } }
下面考慮程序實現。用數組A表示序列A,集合S 不用保存,因為它可以有序列A 完全確定-A中沒有出現的元素都可以選。
代碼:
1 void print_permutation(int n,int*A,int cur) 2 { 3 if(cur==n)//遞歸邊界 4 { 5 for(int i = 0;i<n;i++) 6 { 7 cout << A[i] << " "; 8 } 9 cout << endl; 10 } 11 else 12 { 13 for(int i = 1;i<=n;i++)//嘗試在A中填入各種整數i 14 { 15 int ok = 1; 16 for(int j = 0;j<cur;j++) 17 { 18 if(A[j]==i)//如果i已經在A[0]~A[cur-1]出現過,則不能再選 19 { 20 ok = 0; 21 } 22 } 23 if(ok) 24 { 25 A[cur++] = i; 26 print_permutation(n,A,cur);//遞歸調用 27 cur--; 28 } 29 } 30 } 31 32 }
循環變量i是當前考察的A[cur],上面的程序用到了一個標志變量ok,來看i有沒有在A中出現過,ok為1說明沒有出現就可以把i加到A[cur]處
聲明一個足夠大的數組A,然后調用print_permutation(n,A,0);
2 生成可重集的序列
把問題改成輸入數組P,並按字典序輸出數組A各元素的所有全排列,則需要修改if(A[j]==i)為if(A[j]==P[i]),把A[cur]=i,改成A[cur]=P[i]。
但是如果P中有重復元素就會失效,因為上面的算法是看有無重合元素來判斷P[i]在A[j]中出現過沒有,來決定是不是添加P[i];
可以統計A[0]~A[cur-1]中P[i]出現的次數c1,和P[i]在P數組中出現的次數c2,只要c1<c2,就能遞歸調用。
代碼:
void print_permutation_2(int n,int*P,int*A,int cur) { if(cur==n) { for(int i = 0;i<n;i++) { cout << A[i] << " "; } cout << endl; } else { for(int i = 0;i<n;i++) { if(!i||P[i]!=P[i-1]) { int c1 = 0,c2 = 0; for(int j = 0; j<cur; j++) if(A[j]==P[i]) c1++; for(int j = 0; j<n; j++) if(P[i]==P[j]) c2++; int ok = 1; if(c1<c2) { A[cur++] = P[i]; print_permutation_2(n,P,A,cur); cur--; } } } } }
3 解答樹
遞歸函數的調用可用解答樹來表示,
第0層有n個孩子,第一層n-1個孩子,第二層n-2個孩子,...,第n層為葉節點沒有孩子,每個葉子對應於一個排列,共n!個葉子。
如果某些問題的解可由多個步驟得到,而每個步驟都有若干種選擇,可用遞歸算法實現,他的工作方式可由解答樹描述。
一個重要結論:在多數情況下,解答樹上的節點幾乎全部來自於最后一兩層。和他們相比,上面的節點數可以忽略不計。
4 下一個排列
代碼:
1 void print_permutation_3(int n,int* P) 2 { 3 sort(P,P+n); 4 do{ 5 for(int i = 0;i<n;i++) 6 { 7 cout << P[i] << " "; 8 } 9 cout << endl; 10 }while(next_permutation(P,P+n)); 11 }
代碼匯總:

1 #include <iostream> 2 #include <algorithm> 3 #define max_n 10005 4 using namespace std; 5 int A[max_n]; 6 int P[max_n]; 7 /*void print_permutation(序列A,集合S) 8 { 9 if(S為空) 輸出序列A; 10 else按照從小到大的順序依次考慮S中的每個元素 11 { 12 print_permutation(在A的末尾添加v后得到的新序列,S-{v}); 13 } 14 }*/ 15 void print_permutation(int n,int*A,int cur) 16 { 17 if(cur==n)//遞歸邊界 18 { 19 for(int i = 0;i<n;i++) 20 { 21 cout << A[i] << " "; 22 } 23 cout << endl; 24 } 25 else 26 { 27 for(int i = 1;i<=n;i++)//嘗試在A中填入各種整數i 28 { 29 int ok = 1; 30 for(int j = 0;j<cur;j++) 31 { 32 if(A[j]==i)//如果i已經在A[0]~A[cur-1]出現過,則不能再選 33 { 34 ok = 0; 35 } 36 } 37 if(ok) 38 { 39 A[cur++] = i; 40 print_permutation(n,A,cur);//遞歸調用 41 cur--; 42 } 43 } 44 } 45 46 } 47 void print_permutation_2(int n,int*P,int*A,int cur) 48 { 49 if(cur==n) 50 { 51 for(int i = 0;i<n;i++) 52 { 53 cout << A[i] << " "; 54 } 55 cout << endl; 56 } 57 else 58 { 59 for(int i = 0;i<n;i++) 60 { 61 if(!i||P[i]!=P[i-1]) 62 { 63 int c1 = 0,c2 = 0; 64 for(int j = 0; j<cur; j++) 65 if(A[j]==P[i]) 66 c1++; 67 for(int j = 0; j<n; j++) 68 if(P[i]==P[j]) 69 c2++; 70 int ok = 1; 71 if(c1<c2) 72 { 73 A[cur++] = P[i]; 74 print_permutation_2(n,P,A,cur); 75 cur--; 76 } 77 } 78 } 79 } 80 81 } 82 void print_permutation_3(int n,int* P) 83 { 84 sort(P,P+n); 85 do{ 86 for(int i = 0;i<n;i++) 87 { 88 cout << P[i] << " "; 89 } 90 cout << endl; 91 }while(next_permutation(P,P+n)); 92 } 93 int main() 94 { 95 int P[]={1,2,4,3}; 96 //sort(P,P+4); 97 //print_permutation_2(4,P,A,0); 98 print_permutation_3(4,P); 99 return 0; 100 }