康拓展開介紹

2021-08-09 17:30:37 字數 1905 閱讀 7775

void dfs(int x, int y)

很好奇為啥只需要8步?難道無論怎麼擺放,要達到目標狀態,一定不會超過8步就可以完成麼?我把自己的**也加了這個條件,直接pass。。。震驚!!

帶著這個問題繼續上網搜尋相關資料,了解到這個問題可能無解,也有需要30多步才能解決的。那這樣看來,就是系統的判定case太弱了,所以深度只需要8就可以ac。。

蒐羅了很久,發現網上大部分答案都是bfs,a*…,其中他們用到的康拓展開來儲存狀態,回退狀態。當然我也是把這九個數字組成的狀態對映成乙個數字來儲存,但是感覺就是沒康拓展開來的科學。所以決定看下康拓展開是怎麼一回事。

康拓展開是乙個全排列到乙個自然數的雙射,常用於構建雜湊表時的空間壓縮。康拓展開的實質是計算當前排列在所有由小到大全排列中的順序,並且是可逆的。

比如123的全排列總共6個,通過康拓展開可以計算出由小到大,231排在第幾個。

公式康拓展開就是指把乙個字元、數字序列展開成如下形式:

舉個栗子:

2 5 4 1 3展開為46。因為x=1*4!+33!+2*2!+0*1!+0*0!=46.

解釋:

可見在八數碼問題中,9位數字的排列組合可以通過康拓展開來把他們對映成乙個數,方便儲存和利用,壓縮了空間。

康拓展開**如下:

const

int fac=; //各階乘結果0!,1!,2!,3!,4!...

//康拓展開函式

int cantor(int a, int

len)

ans+=cnt*fac[len-i];

}return ans;

}int main()

; printf("%d", cantor(a,4));

return

0;}

逆康拓展開

假如給你乙個在全排列中排在第幾位的數,求出這個排列組合的具體表示,這便是你康拓展開。還是用上面的**例子。

假如原來的陣列1234,求他排在第24位的組合,如何求? 排序是從0開始,那麼這裡應當首先 24-1 = 23

* 23 / 3! = 3 餘 5, 那麼表示比他小的數有3個,即 4。

* 5 / 2! = 2 餘 1, 那麼表示比他小的數有2個,即 3。

* 1 / 1! = 1 餘 0, 那麼表示比他小的數有1個,即 2。

* 0 / 0! = 0 餘 0, 那麼表示比他小的數有0個,即 1。

* 算出這個組合便是:4321

逆康拓展開**如下:

#include

#define rint register int

const

int fac=; //各階乘結果0!,1!,2!,3!,4!...

void cantorreverse(int a, int len, int k)

;//記錄數字的使用情況

for(rint i = 0; i < len; i++)

a[i] = temp + 1;

vis[temp] = 1;

}}int main()

; int k = 16;

cantorreverse(a, 4, k);

printf("%d %d %d %d",a[0],a[1],a[2],a[3]);

return

0;}

康拓展開和逆展開可以用於把字元,數字的組合排列對映成乙個數字,用於雜湊表的構造,將字串行或者數字序列對映成乙個值或者狀態。

康拓展開和逆康拓展開

康托展開就是一種特殊的雜湊函式 把乙個整數x展開成如下形式 x a n n a n 1 n 1 a 2 2 a 1 1 其中,a為整數,並且0 a表示1,2,3,n的排列如 按從小到大排列一共6種,就是123 132 213 231 312 321 代表的數字 1 2 3 4 5 6 也就是把10進...

康拓展開與逆康拓展開

首先解釋一下,所謂的康拓展開,就是能夠通過乙個式子,得到乙個排列在所有排列中的按字典序排好後的位次。而逆康托展開,則是給出排列的位次,能夠計算出排列是什麼。下面先給出康拓展開的公式 其中ai 為整數,並且 0 ai ai表示原數的第 i位在當前未出現的元素中是排在第幾個 康拓展開是乙個雙射,因此常用...

康拓展開和逆康拓展開

康拓展開模板題 複雜度o n 2 的會tle 看資料就知道了 雖然某題解說可以,不知道是不是後期加強了資料 然而我還是寫了o n 2 的 include typedef long long ll ll f 1000010 const ll mod 998244353 int a 1000010 b ...