日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

n数码问题,全排列的hash(转载

發布時間:2025/4/16 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 n数码问题,全排列的hash(转载 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我們經常使用的數的進制為“常數進制”,即始終逢p進1。例如,p進制數K可表示為
?
?? K = a0*p^0 +a1*p^1 + a2*p^2 + ... + an*p^n (其中0 <= ai<= p-1),
它可以表示任何一個自然數。

對于這種常數進制表示法,以及各種進制之間的轉換大家應該是很熟悉的了,但大家可能很少聽說變進制數。這里我要介紹一種特殊的變進制數,它能夠被用來實現全排列的Hash函數,并且該Hash函數能夠實現完美的防碰撞和空間利用(不會發生碰撞,且所有空間被完全使用)。這種全排列Hash函數也被稱為全排列數化技術。

?

變進制數:

我們考查這樣一種變進制數:第1位逢2進1,第2位逢3進1,……,第n位逢n+1進1。它的表示形式為
?
?? K = a1*1! +a2*2! + a3*3! + ... + an*n! (其中0 <= ai<= i),
也可以擴展為如下形式(因為按定義a0始終為0),以與p進制表示相對應:
?
?? K = a0*0! +a1*1! + a2*2! + a3*3! + ... + an*n! (其中0 <= ai<= i)。
(后面的變進制數均指這種變進制數,且采用前一種表示法)

先讓我們來考查一下該變進制數的進位是否正確。假設變進制數K的第i位ai為i+1,需要進位,而ai*i!=(i+1)*i!=1*(i+1)!,即正確的向高位進1。這說明該變進制數能夠正確進位,從而是一種合法的計數方式。

?

n位變進制數K的性質:
(1)當所有位ai均為i時,此時K有最大值
?
?? MAX[K] =1*1! + 2*2! + 3*3! + ... + n*n!
?
?????????= 1! + 1*1! + 2*2! + 3*3! + ... + n*n! - 1
?
?????????= (1+1)*1! + 2*2! + 3*3! + ... + n*n! - 1
?
?????????= 2! + 2*2! + 3*3! + ... + n*n! - 1
?
?????????= ...
?
?????????= (n+1)!-1
?
??因此,n位K進制數的(9php.com)最大值為(n+1)!-1。
(2)當所有位ai均為0時,此時K有最小值0。
因此,n位變進制數能夠表示0到(n+1)!-1的范圍內的所有自然數,共(n+1)!個。

ps:全排列的Hash函數完美利用空間防碰撞的前提。

?

全排列的Hash函數:

在一些狀態空間搜索算法中,我們需要快速判斷某個狀態是否已經出現,此時常常使用Hash函數來實現。其中,有一類特殊的狀態空間,它們是由全排列產生的,比如N數碼問題。對于n個元素的全排列,共產生n!個不同的排列或狀態。下面將討論如何使用這里的變進制數來實現一個針對全排列的Hash函數。

從數的角度來看,全排列和變進制數都用到了階乘。如果我們能夠用0到n!-1這n!個連續的變進制數來表示n個元素的所有排列,那么就能夠把全排列完全地數化,建立起全排列和自然數之間一一對應的關系,也就實現了一個完美的Hash函數。那么,我們的想法能否實現呢?答案是肯定的,下面將進行討論。

假設我們有b0,b1,b2...bn 共 n+1 個不同的元素,假設各元素之間有一種次序關系b0< b1 < b2 ...<bn。對它們進行全排列,共產生(n+1)!種不同的排列。對于產生的任一排列 c0,c1,c2,..,cn,其中第i個元素ci(1<= i <= n)與它前面的i個元素構成的逆序對的個數為di(0<= di <= i),那么我們得到一個逆序數序列d1,d2,...,dn(0 <= di<=i)。這不就是前面的n位變進制數的各個位么?于是,我們用n位變進制數M來表示該排列:
?
? M = d1*1! + d2*2! + ... +dn*n!
因此,每個排列都可以按這種方式表示成一個n位變進制數。下面,我們來考查n位變進制數能否與n+1個元素的全排列建立起一一對應的關系。

由于n位變進制數能表示(n+1)!個不同的數,而n+1個元素的全排列剛好有(n+1)!個不同的排列,且每一個排列都已經能表示成一個n位變進制數。如果我們能夠證明任意兩個不同的排列產生兩個不同的變進制數,那么我們就可以得出結論:
★ 定理1 n+1個元素的全排列的每一個排列對應著一個不同的n位變進制數。

對于全排列的任意兩個不同的排列p0,p1,p2,...,pn(排列P)和q0,q1,q2,...,qn(排列Q),從后往前查找第一個不相同的元素,分別記為pi和qi(0< i <= n)。
(1)如果qi > pi,那么,
如果在排列Q中qi之前的元素x與qi構成逆序對,即有x > qi,則在排列P中pi之前也有相同元素x> pi(因為x > qi且qi >pi),即在排列P中pi之前的元素x也與pi構成逆序對,所以pi的逆序數大于等于qi的逆序數。又qi與pi在排列P中構成pi的逆序對,所以pi的逆序數大于qi的逆序數。
(2)同理,如果pi > qi,那么qi的逆序數大于pi的逆序數。
因此,由(1)和(2)知,排列P和排列Q對應的變進制數至少有第i位不相同,即全排列的(9php.com)任意兩個不同的(9php.com)排列具有不同的變進制數。至此,定理1得證。

?

計算n個元素的一個排列的變進制數的算法大致如下(時間復雜度為O(n^2)):
template <typename T>
size_t PermutationToNumber(const T permutation[], int n)
{
?
?? //n不能太大,否則會溢出(如果size_t為32位,則n <=12
?
?? size_tresult = 0;
?
?? for (int j =1; j < n; ++j) {
?
??????int count = 0;
?
??????for (int k = 0; k < j; ++k) {
?
??????????if (permutation[k] > permutation[j])
?
??????????????++count;
?
??????}
?
??????// factorials[j]保存著j!
?
??????result += count * factorials[j];
?
?? }

??? returnresult;
}

說明:
(1)由于n!是一個很大的數,因此一般只能用于較小的n。
(2)有了計算排列的變進制數的算法,我們就可以使用一個大小為n!的數組來保存每一個排列的狀態,使用排列的變進制數作為數組下標,從而實現狀態的快速檢索。如果只是標記狀態是否出現,則可以用一位來標記狀態。


總結

以上是生活随笔為你收集整理的n数码问题,全排列的hash(转载的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。