隨機洗牌算法Knuth Shuffle和錯排公式
阿新 • • 發佈:2018-08-16
定義 方法 wap style 交換 如何 -- 自己 spa
Knuth隨機洗牌算法:譬如現在有54張牌,如何洗牌才能保證隨機性。可以這麽考慮,從最末尾一張牌開始洗,對於每一張牌,編號在該牌前面的牌中任意一張選一張和當前牌進行交換,直至洗到第一張牌為止。參考代碼如下:
void knuth() { for (int i = 54; i > 1; i--) { int id = rand() % (i - 1) + 1; swap(a[i], a[id]); } }
由上述方法可知,每一張牌經過洗牌之後一定不會出現在原來位置,那麽一共會有多少情況呢,這其實就是錯排的定義,n個數的錯排數有如下遞推公式:
f(n)=(n-1)(f(n-1)+f(n-2))
公式的推導:首先讓我們假設已知n-1個數和n-2個數的錯排數,這時又在原來基礎上加了一個數字,那麽如果這n個數要構成錯排,新加入的數字一定不能出現在自己的位置上,所以它只能選擇其余的n-1個位置,不妨設選擇了第k個位置,那麽原本在第k個位置上的數又會跑到哪裏去呢,這裏有兩種情況,原本的第k個數跑到第n個數的位置上去了,這時這兩個數只是相互交換了位置,其余的n-2個數怎麽排列完全不受影響,故此時有f(n-2)種情況;再考慮原本第k個數不在第n個數的位置上,那麽除去第n個數,其余的n-1個數任然構成錯排,錯排數為f(n-1)。至此就可得遞推式f(n)=(n-1)(f(n-1)+f(n-2));
隨機洗牌算法Knuth Shuffle和錯排公式