做到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;
}