1. 程式人生 > 程式設計 >C++全排列中遞迴交換法例項詳解

C++全排列中遞迴交換法例項詳解

對於求解全排列問題有最暴力的遞迴列舉法,但是我們希望可以優化時間,因此出現了遞迴交換法。

例題

洛谷1706

題目描述

輸出自然數1到n所有不重複的排列,即n的全排列,要求所產生的任一數字序列中不允許出現重複的數字。

輸入格式

一個整數n。

輸出格式

由1~n組成的所有不重複的數字序列,每行一個序列。

每個數字保留 5個場寬。

輸入樣例

3

輸出樣例

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

全排列問題——遞迴交換法

其實跟暴力列舉思路差不多,每次遞迴列舉第x個數字是幾,之後a[x]可以選擇不動,也可以選擇與後面任意一個數交換位置,就是從後面選一個數放到x的位置上。

簡而言之,就是每到一位就從後面選一個尚未被使用過的數字與該位數字交換,這裡有些難理解,您可以自己按照程式推一下樣例。

這樣我們就可以列印所有的全排列了,但這樣不是按順序列印,所以這裡需要每次對a[x] ~ a[n]進行排序。

舉個例子,如對1、2、3進行全排列。當我們交換1和3後,序列變為3、2、1,如果說這裡不排序,直接2、1都保持不動,就輸出3、2、1了,可是我們先要的應該是3、1、2,所以要進行排序。

最後,算一下時間複雜度,我們發現需要從1到n一位一位的看,之後每位還要列舉x ~ n,所以總時間複雜度為O(n!)。

程式碼

# include <cstdio>
# include <cmath>
# include <cstring>
# include <algorithm>

using namespace std;

const int N_MAX = 10;

int n;
int a[N_MAX + 10];

void permutation(int x)
{
 if (x == n) {
  for (int i = 1; i <= n; i++)
   printf("%5d",a[i]);
  printf("\n");
  return;
 }
 for (int i = x; i <= n; i++) {
  sort(a + x,a + n + 1);
  swap(a[x],a[i]);
  permutation(x + 1);
  swap(a[x],a[i]);
 }
}

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

以上就是小編給大家整理的全部相關知識點,感謝大家對我們的支援。