【学习随笔】Cantor 展开式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/QingCoffe/article/details/84346620

做到HDOJ1043的时候接触到了Cantor展开式,因为开始在用BFS+hash 做的,因此在四向搜索的时候需要判重,需要知道

当前方向的这种九宫情况是否之前被访问过,但是...九宫的总情况大概有9!个36W多个,因此判重非常的烦,看了网上的

基本都是手写的,用数组模拟 hash table ,hash 最重要的就是hash函数来得到序列号,因为九宫不存在重复数,因此每种

情况可以当做一个全排序,因此Cantor来了...通过这下列操作可以得出每一种九宫情况的序列号而不会重复,来作为hash

序列号..很nice的操作!

Cantor展开:

X=an*(n-1)!+an-1*(n-2)!+…+ai*(i-1)!+…+a2*1!+a1*0!

使用示例来帮助理解利用Cantor展开如何求解本问题。 
假如序列s=[“A”,”B”,”C”,”D”] 
需要求序列s’=[“D”,”A”,”B”,”C”]是序列s的全排列中的第几个排列,记作X(s’);

X(s’) =     3(在序列DABC中有3个比D小)*3!+
            0(在剩下的序列ABC中有0个比A小)*2!+
            0(在剩下的序列BC中有0个比B小)*1!+
            0(在剩下的序列C中有0个比C小)*0!
    =18

那么序列s’是s的全排列中第18个排列(从0开始计数); 
同理可以根据s算第18个排列序列。 

总结:康托展开是一个全排列到一个自然数的一一映射

下列代码转自 https://www.cnblogs.com/AdaByron/archive/2011/09/21/2200970.html 

正向展开:

//value数组存放当前排列   
const int fac[]={1,1,2,6,24,120,720,5040,40320};//康托序列   
inline int cantor(){  
    int ans=0;  
    for(int i=0;i<N;i++)  
    {  
        int cnt=0;  
        for(int k=i+1;k<N;k++)  
        {  
            if(value[k]<value[i])  
                cnt++;  
        }  
        ans+=fac[8-i]*cnt;  
    }  
    return ans;  
}

反向展开:

//value数组存放当前排列   
const int fac[]={1,1,2,6,24,120,720,5040,40320};//康托序列   
inline int cantor(Point p){  
    int ans=0;  
    for(int i=0;i<N;i++)  
    {  
        int cnt=0;  
        for(int k=i-1;k>=0;k--)  
        {  
            if(value[k]>value[i])  
                cnt++;  
        }  
        ans+=fac[i]*cnt;  
    }  
    return ans;  
}

猜你喜欢

转载自blog.csdn.net/QingCoffe/article/details/84346620