【學習隨筆】Cantor 展開式
阿新 • • 發佈:2018-12-02
做到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;
}