康託展開 全排列

今天找到了一篇非常好的介紹康託展開的文章!!!
http://www.cnblogs.com/1-2-3/archive/2011/04/25/generate-permutation-part2.html
其核心是這一張圖:
Cantor

根據這篇文章,寫出生成按序排列的全排列非常的簡單:

#include <iostream>
#include <vector>
#include <string>

#define N 4

using namespace std;

vector<char> letter;                //存儲所需字母表

void initLetter()                   //初始化字母表
{
    for(int i = 0; i < N; ++i){
        letter.push_back('A' + i);
    }
}

int fact(int n)                     //階乘
{
    int result = 1;
    for(int i = 1; i <= n; ++i){
        result *= i;
    }
    return result;
}

void output(vector<char>& v)        //輸出生成的結果
{
    for(vector<char>::iterator it = v.begin(); it != v.end(); ++it){
        cout << *it;
    }
    cout << endl;
}

void division(int n)                //核心算法:輾轉相除生成排列
{
    initLetter();                   //每次先初始化字母表
    vector<char> result;

    int value, div;
    for(int i = N - 1; i >= 0; --i){            //從(N-1)!除起
        div = fact(i);
        value = n / div;                        //商爲當前字母表下標
        n = n % div;                            //餘數繼續用於輾轉相除
        result.push_back(letter[value]);        //商對應的字母加入到結果
        letter.erase(letter.begin() + value);   //從原始字母表中刪除(參數必須是iterator)
    }
    output(result);
}

int main()
{
    int num = fact(N);
    for(int i = 0; i < num; i++){   //從0~(N! - 1),每一個數對應一個排列
        division(i);
    }
    return 0;
}

和原來的通過遞歸+回溯(http://blog.csdn.net/puppylpg/article/details/45287249)來生成全排列相比思路上簡單了不少!

#include <iostream>
#include <vector>

#define N 4

using namespace std;

vector<char> letter;                //存儲所需字母表
vector<bool> visited;               //標記

vector<char> result;

void initLetter()                   //初始化字母表
{
    for(int i = 0; i < N; ++i){
        letter.push_back('A' + i);
        visited.push_back(false);
        result.push_back(' ');      //順便給result開闢空間
    }
}

void output(vector<char>& v)        //輸出生成的結果
{
    for(vector<char>::iterator it = v.begin(); it != v.end(); ++it){
        cout << *it;
    }
    cout << endl;
}

void f(int n)                 //核心算法:回溯。n是第n位
{
    if(n == N){               //如果已經放置了N位,說明生成了一個排列
        output(result);
        return;
    }

    for(int i = 0; i < N; i++){     //對於每一位
        if(visited[i] == false){    //如果沒有被用過,則可以用
            visited[i] = true;
            result[n] = letter[i];
            f(n + 1);               //遞歸繼續生成下一位
            visited[i] = false;     //回溯
        }
    }
}

int main()
{
    initLetter();
    f(0);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章