1. 程式人生 > >【萬能搜尋】萬能DFS之全排列(一)——普通演算法

【萬能搜尋】萬能DFS之全排列(一)——普通演算法

DFS相信大家都很熟悉,下面就給出一種用DFS實現的演算法。

全排列

大家對於全排列是很熟悉的,比如123的全排列就有:

123
132
213
231
312
321

這六種。
現在,我們來設計一個演算法,來求出所有全排列。

一個暴力演算法

在全排列中,我們只需不停地試每一個元素所在的位置,再根據全排列中同一元素只出現一次,就可以暴力枚舉出全排列。

//暴力實現
bool check(int x,int i)
{
    for(int k=1;k<=x;k++)
        if(ans[k]==a[x])return
0; return 1; } void dfs(int x) { if(x>n) { Print();//輸出 return;//千萬不要打掉這句 //不打會將一個排列輸出兩次 } for(int i=1;i<=n;i++)//n是長度 if(check(x,i)) { ans[x]=a[i]; dfs(x+1); } }

不難看出,這個演算法時間複雜度為O(n2×n!)。非常慢。

暴力演算法v2.0

其實我們可以仔細想想,在ans陣列中,每個元素只對應原陣列的唯一一個位置,所以,我們就可以利用這一性質,用O(1)的時間來找出值。

//暴力實現v2.0
void dfs(int x)
{
    if(x>n)
    {
        Print();
        return;
    }
    for(int i=1;i<=n;i++)
        if(!bo[i])
        {
            ans[x]=a[i];
            bo[i]=1;
            dfs(x+1);
            bo[i]=0
;//不打這句你會死得很慘 } }

這個演算法時間複雜度也比較慢,為O(n×n!)

一個看上去很NB的演算法

先給程式碼:

#include<cstdio>
#include<algorithm>
using namespace std;
int a[101],n;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    do Print();
    while(next_permutation(a+1,a+n+1));
    return 0;
}

是很NB吧,還自帶字典序輸出。沒錯,這就是萬能的algorithm庫裡面的next_permutation函式!它能在O(n!)的時間複雜度求出所有全排列!這是已知的、最快的求出全排列的方法。還可以處理重複元素!
關於這個演算法的實現方法,我們下節再論。
搜尋系列文章:
1. 【未完】【萬能搜尋】萬能DFS之全排列(二)——next_permutation詳解
2. 【未完】【萬能搜尋】萬能BFS之最短路(一)——走迷宮
3. 【未完】【萬能搜尋】萬能BFS之最短路(二)——詳解八數碼問題