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

Cantor expansion

时间:2015-07-25 07:05:20      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:

Cantor expansion的本质是将一个排列hash成为一个数,这个数就是这个排列rank值,将原本需要用nn的空间来记录的排列状态在n!的空间内记录下来,有效利用了空白的空间。而将排列变为排名的桥梁便是展开后的那个an数组。其实原理非常简单,但是对于解决类似N数码问题等牵涉的排列状态记录的问题时特别有用。

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 9;//保存排列的长度
int fac[maxn + 1];//保存阶乘
/*
*康托展开的值与实际rank值相差1
*/
void initfac(){//初始化阶乘
    fac[0] = 1;
    for (int i = 1; i <= maxn; i++){
        fac[i] = fac[i - 1] * i;
    }
}

int cantorEncode(const int a[]){//将排列逆康托展开,排列下标从1开始,所得值为rank
    bool flag[maxn + 1] = { false };
    int x = 0;
    for (int i = 1; i <= maxn; i++){
        int cnt = 0;
        for (int j = i + 1; j <= maxn; j++){
            if (!flag[j]){
                flag[j] = true;
                cnt++;
            }
        }
        x += fac[maxn - i] * cnt;
    }
    return x+1;
}
void cantorDecode(int rank, int a[]){//将x=rank-1康托展开,保存到a[]中,下标从1开始
    rank--;
    int tmp[maxn + 1] = { 0 };
    for (int i = 1; i <= maxn; i++){
        tmp[i] = rank / fac[maxn - i];
        rank -= fac[maxn - i] * tmp[i];
    }
    bool flag[maxn + 1] = { false };
    for (int i = 1; i <= maxn; i++){
        int cnt = 0;
        for (int j = 1; j <= maxn;j++){
            if (!flag[j]){
                cnt++;
                if (cnt == tmp[i]+1){
                    a[i] = j;
                    flag[j] = true;
                    break;
                }
            }
        }
    }
}
void printArray(int a[]){
    for (int i = 1; i <= maxn; i++){
        printf("%d%c", a[i], " \n"[i == maxn]);
    }
}

 

 


 

康托展开就是一种特殊的哈希函数

  把一个整数X展开成如下形式:

  X=a[n]*n!+a[n-1]*(n-1)!+...+a[2]*2!+a[1]*1!

  其中,a为整数,并且0<=a<i,i=1,2,..,n

  {1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按从小到大排列一共6个。123 132 213 231 312 321 。

  代表的数字 1 2 3 4 5 6 也就是把10进制数与一个排列对应起来。

  他们间的对应关系可由康托展开来找到。

  如我想知道321是{1,2,3}中第几个大的数可以这样考虑 :

  第一位是3,当第一位的数小于3时,那排列数小于321 如 123、 213 ,小于3的数有1、2 。所以有2*2!个。再看小于第二位2的:小于2的数只有一个就是1 ,所以有1*1!=1 所以小于321的{1,2,3}排列数有2*2!+1*1!=5个 
。所以321是第6个大的数。 2*2!+1*1!是康托展开。

  再举个例子:1324是{1,2,3,4}排列数中第几个大的数:第一位是1小于1的数没有,是0个 0*3! 第二位是3小于3的数有1和2,但1已经在第一位了,所以只有一个数2 1*2! 。第三位是2小于2的数是1,但1在第一位,所以 
有0个数 0*1! ,所以比1324小的排列有0*3!+1*2!+0*1!=2个,1324是第三个大数。

Cantor expansion

标签:

原文地址:http://www.cnblogs.com/-myths/p/4675164.html

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