您的位置:首页 > 其它

康托展开 全排列

2016-04-27 15:59 483 查看
今天找到了一篇非常好的介绍康托展开的文章!!!

http://www.cnblogs.com/1-2-3/archive/2011/04/25/generate-permutation-part2.html

其核心是这一张图:



根据这篇文章,写出生成按序排列的全排列非常的简单:

#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
= letter[i];
f(n + 1);               //递归继续生成下一位
visited[i] = false;     //回溯
}
}
}

int main()
{
initLetter();
f(0);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  康托展开 全排列