码迷,mamicode.com
首页 > 其他好文 > 详细

康托展开

时间:2015-07-20 22:53:43      阅读:194      评论:0      收藏:0      [点我收藏+]

标签:

康托展开

  康托展开的公式是 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 其中,ai为当前未出现的元素中是排在第几个(从0开始)。
  这个公式可能看着让人头大,最好举个例子来说明一下。例如,有一个数组 s = ["A", "B", "C", "D"],它的一个排列 s1 = ["D", "B", "A", "C"],现在要把 s1 映射成 X。n 指的是数组的长度,也就是4,所以
X(s1) = a4*3! + a3*2! + a2*1! + a1*0!
关键问题是 a4、a3、a2 和 a1 等于啥?
a4 = "D" 这个元素在子数组 ["D", "B", "A", "C"] 中是第几大的元素。"A"是第0大的元素,"B"是第1大的元素,"C" 是第2大的元素,"D"是第3大的元素,所以 a4 = 3。
a3 = "B" 这个元素在子数组 ["B", "A", "C"] 中是第几大的元素。"A"是第0大的元素,"B"是第1大的元素,"C" 是第2大的元素,所以 a3 = 1。
a2 = "A" 这个元素在子数组 ["A", "C"] 中是第几大的元素。"A"是第0大的元素,"C"是第1大的元素,所以 a2 = 0。
a1 = "C" 这个元素在子数组 ["C"] 中是第几大的元素。"C" 是第0大的元素,所以 a1 = 0。(因为子数组只有1个元素,所以a1总是为0)
所以,X(s1) = 3*3! + 1*2! + 0*1! + 0*0! = 20


A B C | 0
A C B | 1
B A C | 2
B C A | 3
C A B | 4
C B A | 5

通过康托逆展开生成全排列

  如果已知 s = ["A", "B", "C", "D"],X(s1) = 20,能否推出 s1 = ["D", "B", "A", "C"] 呢?
  因为已知 X(s1) = a4*3! + a3*2! + a2*1! + a1*0! = 20,所以问题变成由 20 能否唯一地映射出一组 a4、a3、a2、a1?如果不考虑 ai 的取值范围,有
3*3! + 1*2! + 0*1! + 0*0! = 20
2*3! + 4*2! + 0*1! + 0*0! = 20
1*3! + 7*2! + 0*1! + 0*0! = 20
0*3! + 10*2! + 0*1! + 0*0! = 20
0*3! + 0*2! + 20*1! + 0*0! = 20
等等。但是满足 0 <= ai <= n-1 的只有第一组。可以使用辗转相除的方法得到 ai,如下图所示:
技术分享
知道了a4、a3、a2、a1的值,就可以知道s1[0] 是子数组["A", "B", "C", "D"]中第3大的元素 "D",s1[1] 是子数组 ["A", "B", "C"] 中第1大的元素"B",s1[2] 是子数组 ["A", "C"] 中第0大的元素"A",s[3] 是子数组 ["C"] 中第0大的元素"C",所以s1 = ["D", "B", "A", "C"]。
这样我们就能写出一个函数 Permutation3(),它可以返回  s 的第 m 个排列。

前面的内容从http://archive.cnblogs.com/a/2026276/转载

#include<iostream>
#include<cstdio>
using namespace std;
//用康拓展开求全排列s的第m个序列(s中每个元素要不同,用1-n表示)
class cantor{
public:
    //要求n<=12
    int n;
    int fac[20];
    int num[20];
    cantor(int n):n(n)
    {
        fac[0]=1;
        for(int i=0;i<n;i++){
            num[i]=i;
        }
        for(int i=1;i<n;i++){
            fac[i]=fac[i-1]*i;
        }
    }
    int encode(string s)
    {
        int vec[20];
        if(s.size()!=n)
            return -1;//不符合要求
        for(int i=0;i<n;i++){
            int cnt=0;
            for(int j=i;j<n;j++)
                if(s[i]>s[j])cnt++;
            vec[n-i-1]=cnt;
        }
        int pos=0;
        for(int i=0;i<s.size();i++)
            pos+=vec[i]*fac[i];
        return pos;
    }
    string decode(int pos)
    {
        string s="";
        int re,yu;//商和余数
        for(int i=n-1;i>=0;i--)
        {
            re=pos/fac[i];
            yu=pos%fac[i];
            s+=char(num[re]);
            for(int j=re;j<n-1;j++)
            {
                num[j]=num[j+1];
            }
            pos=yu;
        }
        return s;
    }
};
int main()
{
    cantor t(6);
    string s=t.decode(3);
    for(int i=0;i<s.size();i++)
    {
        printf("%d ",s[i]);
    }
    puts("");
    return 0;
}

 

康托展开

标签:

原文地址:http://www.cnblogs.com/kylehz/p/4662666.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!