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 ...