关于如何评价洗牌质量的猜想
關(guān)于如何評(píng)價(jià)洗牌質(zhì)量的猜想
?
洗牌算法是卡牌類游戲中必須使用的算法,本質(zhì)上說(shuō)洗牌算法的目的是使某個(gè)給定的順序更加的無(wú)序,因此出現(xiàn)了很多種洗牌算法。我們不重點(diǎn)討論如何洗牌,我們將眼光關(guān)注于洗出的牌是否達(dá)到我們預(yù)期的要求,以及如何衡量洗出的牌無(wú)序的程度。首先先看一個(gè)簡(jiǎn)單有效的洗牌算法。
一、一個(gè)簡(jiǎn)單的洗牌算法
一個(gè)比較容易實(shí)現(xiàn)的洗牌算法是這樣的,通過(guò)隨機(jī)選出兩張牌進(jìn)行交換,通過(guò)多次這樣的重復(fù)操作,就能達(dá)到洗牌的目的。事實(shí)證明這種洗牌方式還是比較可行,最重要的是比較簡(jiǎn)單,代碼如下。
//洗牌算法,隨機(jī)交換數(shù)組的兩個(gè)元素,交換數(shù)組長(zhǎng)度次為一次洗牌template<class?T>
void?mess(T?data[],unsigned?int?len)
{
????int?i=len,j,k;
????T?t;
????srand((unsigned?int)time(0));//隨機(jī)因子
????while(i--)//交換牌數(shù)次數(shù)
????{
????????while(true)//找出兩張不一樣的牌
????????{
????????????//隨機(jī)產(chǎn)生兩張牌
????????????j=rand()%len;
????????????k=rand()%len;
????????????if(j!=k)//不是同一個(gè)元素
????????????{
????????????????//交換
????????????????t=data[j];
????????????????data[j]=data[k];
????????????????data[k]=t;
????????????????//退出進(jìn)行下一次交換
????????????????break;
????????????}
????????}
????}
}
這種算法通過(guò)對(duì)有序的(假設(shè)開(kāi)始洗牌時(shí)是有序的,并以此為參考)N張牌進(jìn)行N次隨機(jī)交換,事實(shí)達(dá)到了洗牌的目的。以下是一個(gè)20位有序牌幾次洗牌后的結(jié)果:
雖然得到了我們想要的洗牌效果,但是我們卻無(wú)法定量的衡量洗出牌的質(zhì)量。換句話說(shuō)就是如何確定洗出的牌究竟亂成什么樣子?為了驗(yàn)證洗牌的質(zhì)量,必須給出評(píng)價(jià)洗出的牌的一個(gè)定量的分析。?
二、如何評(píng)價(jià)洗出牌的質(zhì)量
牌洗出什么樣子才算比較好,當(dāng)然是越亂越好。但是這么說(shuō)其實(shí)并不全面,在實(shí)際的卡牌游戲中,我們要達(dá)到的目的只需要保證下局游戲時(shí)洗出的牌要和洗牌之前的情形變化很大即可,這個(gè)就是洗牌算法的本身需要考慮的問(wèn)題。假如給我們一副新的牌,內(nèi)部是按照某個(gè)順序排列的,洗牌算法要達(dá)到的目的是盡量讓它混亂,但是混亂的結(jié)果如何呢?所以不論在任何情況下,計(jì)算出牌的混亂程度都是必須的,它可以為我們的進(jìn)行其他流程提供參考。因此,歸根結(jié)底還是需要討論洗出牌的混亂程度。為了方便討論這個(gè)問(wèn)題,我們有個(gè)基本假設(shè):如果按照某個(gè)順序,無(wú)論是升序還是降序,這種順序的牌的混亂程度應(yīng)該定義為0。很明顯,有序的牌是不混亂的,那么下邊就需要討論混亂的牌的混亂程度怎么計(jì)算。
繼續(xù)討論之前,首先我們定義一個(gè)新的名詞——混亂度[Degree of Chaos](無(wú)序度),記為Ch。這個(gè)概念類似于物理學(xué)中的熵。然后,我們把牌抽象為一個(gè)一維數(shù)組,數(shù)組初始值是按照自然數(shù)有序的,即1、2、3、4、5……這樣,我們討論的問(wèn)題就變成了對(duì)一個(gè)無(wú)序數(shù)組的處理并得到一個(gè)混亂度的問(wèn)題了。混亂度如何定義才比較合適呢?結(jié)合上述的洗牌算法,我有個(gè)大膽的猜想,給出混亂度的定義:
定義:無(wú)序序列通過(guò)交換兩個(gè)內(nèi)部元素還原為有序序列需要的最小次數(shù)。
這里定義有兩個(gè)關(guān)鍵點(diǎn),一個(gè)是通過(guò)交換兩個(gè)元素還原為有序,另一個(gè)是最小次數(shù)。前者說(shuō)明了評(píng)價(jià)無(wú)序序列的方式,即通過(guò)還原序列為有序進(jìn)行交換元素,后者說(shuō)明了若一個(gè)序列越混亂則越難還原為有序的序列,需要的次數(shù)越多,同時(shí)包含了還原為升序和降序序列需要的最小次數(shù)。
例如:對(duì)于序列A=(1,4,2,3,5),需要交換<3,4>、<2,3>兩次才能還原為有序序列A0=(1,2,3,4,5)。當(dāng)然還有其他的還原步驟,也可以還原為B0=(5,4,3,2,1)。但是不管怎么還原,需要的步數(shù)最好是2,即Ch(A)=2。
雖然能按照這種方式得到混亂度,但是如何通過(guò)定量的計(jì)算得到混亂度呢?因?yàn)檫@直接關(guān)系著程序設(shè)計(jì)的能否實(shí)現(xiàn)的問(wèn)題。
三、混亂度的計(jì)算Ch(A)
計(jì)算混亂度之前,首先我們需要思考混亂度的定義。混亂度強(qiáng)調(diào)最少交換次數(shù)變?yōu)橛行蛐蛄小T谒惴ㄔO(shè)計(jì)中,排序是很經(jīng)典的問(wèn)題了,排序算法數(shù)不勝數(shù)。我們期待的是能否通過(guò)排序算法的計(jì)算得到混亂度。既然是最少交換次數(shù),我們首先想到的或許是快速排序算法,畢竟它是目前性能最好的排序算法。但是經(jīng)過(guò)驗(yàn)證它并不合適,單純的將元素按照中軸元素進(jìn)行分割只會(huì)加大交換次數(shù)。然后我們嘗試經(jīng)典的排序算法——冒泡排序,事實(shí)證明也不行,因?yàn)槊芭菖判蛎看味家M(jìn)行交換,做了很多無(wú)用功。最后我們會(huì)想到選擇排序,它的算法性能并不好,但是經(jīng)過(guò)我們的驗(yàn)證,它是最可能接近我們期待答案的排序算法。為什么呢?改進(jìn)后的選擇排序算法思想大致可以這么描述:通過(guò)按序?qū)?shù)組的某一個(gè)元素與后邊的元素比較,最后拿到最小(大)元素與本身交換,最終達(dá)到有序。假設(shè)數(shù)組大小是N,則根據(jù)選擇排序算法,最大的交換次數(shù)不會(huì)大于N-1(最后一個(gè)元素不需要交換)。還拿剛才那個(gè)例子,A=(1,4,2,3,5),按照選擇排序算法,通過(guò)交換<4,2>、<4,3>也能達(dá)到有序,而且也是2步!看起來(lái)選擇算法能計(jì)算出我們想要的混亂度,通過(guò)下邊的實(shí)驗(yàn)可以求出任意序列的混亂度,并能進(jìn)一步驗(yàn)證我們的猜想。
首先,我們需要通過(guò)選擇排序計(jì)算混亂度。算法大致如下:
//計(jì)算數(shù)組的混亂程度:無(wú)需數(shù)組通過(guò)交換元素恢復(fù)到有序(升序和降序)數(shù)組需要的最少交換次數(shù)//暫時(shí)使用選擇排序交換的次數(shù)進(jìn)行計(jì)算,捎帶驗(yàn)證
template<class?T>
int?messDegree(const?T?data[],const?unsigned?int?len)
{
????T*upData=new?T[len];//升序數(shù)據(jù)
????T*downData=new?T[len];//降序數(shù)據(jù)
????int?degree;//混亂度
????unsigned?int?i,j,upK,downK,upSum=0,downSum=0;
????T?t;
????//拷貝數(shù)據(jù)
????for(i=0;i<len;i++)
????{
????????upData[i]=downData[i]=data[i];
????}
????//排序計(jì)算
????for(i=0;i<len-1;i++)
????{
????????upK=downK=i;
????????for(j=i+1;j<len;j++)
????????{
????????????if(upData[j]<upData[upK])//有更小的
????????????????upK=j;
????????????if(downData[j]>downData[downK])//有更大的
????????????????downK=j;
????????}
????????if(upK!=i)
????????{
????????????t=upData[i];
????????????upData[i]=upData[upK];
????????????upData[upK]=t;
????????????upSum++;//計(jì)算升序交換次數(shù)
????????}
????????if(downK!=i)
????????{
????????????t=downData[i];
????????????downData[i]=downData[downK];
????????????downData[downK]=t;
????????????downSum++;//計(jì)算降序交換次數(shù)
????????}
????}
????degree=upSum<downSum?upSum:downSum;//取最小值
????delete[]?upData;
????delete[]?downData;
????return?degree;
}
對(duì)通過(guò)選擇排序得到的結(jié)果是否就是混亂度進(jìn)行證明并不是很容易,本人知識(shí)有限,希望有高人出現(xiàn)幫我證明這個(gè)命題。下邊討論內(nèi)容的前提是默認(rèn)選擇排序的方法是正確的。
四、最大混亂度Ch(N)
我們得到了混亂度的計(jì)算方法,針對(duì)有序序列A0=(1,2,3…),混亂度Ch(A0)=0。但是對(duì)于N維序列A,它的最大的混亂度Ch(N)是多少,這個(gè)能否計(jì)算呢?要知道,按照混亂度的定義,最大的混亂度代表著序列的最無(wú)序的狀態(tài),相應(yīng)的也就代表牌被洗得不能再洗的情況,所以,最大混亂度有它實(shí)際的含義。但是計(jì)算最大混亂度目前還沒(méi)有比較直接的公式可以使用,既然如此,我們就使用計(jì)算機(jī)枚舉所有可能的序列來(lái)計(jì)算一部分最大混亂度。
我們將計(jì)算混亂度的算法嵌入到n階排列算法中,于是得到所有的n!個(gè)排列對(duì)應(yīng)的混亂度。由于我們只關(guān)心最大的混亂度Ch(N),所以算法只記錄了Ch(N)。
//構(gòu)造所有排列,求最大需要的交換個(gè)數(shù)——最大混亂度template<class?T>
void?perm(T?data[],int?k,int?m,int?&max,int?len)
{
????if(k==m)//一個(gè)排列出現(xiàn)
????{
????????int?t=messDegree(data,len);//計(jì)算混亂度
????????if(max<t)
????????????max=t;//記錄最大混亂度
????????return?;
????}
????else
????{
????????for(int?i=k;i<=m;i++)
????????{
????????????int?t=data[i];
????????????data[i]=data[k];
????????????data[k]=t;
????????????perm(data,k+1,m,max,len);
????????????t=data[i];
????????????data[i]=data[k];
????????????data[k]=t;
????????}
????}
}
對(duì)于N維序列,枚舉出所有的可能序列是個(gè)排列問(wèn)題,時(shí)間復(fù)雜度是O(n!)。因此算法的復(fù)雜度相當(dāng)高,受限于機(jī)器能力,我只測(cè)試到N=11時(shí)對(duì)應(yīng)的Ch(N)。由于3個(gè)元素一下的序列不存在混亂的問(wèn)題,很明顯Ch(1)=Ch(2)=0。所以討論N≥3情況下的Ch(N)才有實(shí)際意義。以下是枚舉所有情況得到的Ch(n):
Ch(3)=1、Ch(4)=3、Ch(5)=4、Ch(6)=4、Ch(7)=5、Ch(8)=7、Ch(9)=8、Ch(10)=8、Ch(11)=9。
得到這個(gè)結(jié)果其實(shí)并不令人滿意,本想從中找到一些規(guī)律來(lái)更好地計(jì)算最大混亂度的希望破滅了。
五、總結(jié)
本文從洗牌算法中引申出如何評(píng)價(jià)洗出的牌質(zhì)量的方法,首先引入概念——混亂度,然后提出通過(guò)按照選擇排序算法進(jìn)行計(jì)算混亂度的猜想,最后使用窮舉的方式求解了簡(jiǎn)單的序列的最大混亂度Ch(N)。遺憾的是筆者并沒(méi)有給出選擇排序算法計(jì)算混亂度是否正確的形式化證明和最大混亂度的簡(jiǎn)便計(jì)算方法。希望基于筆者的想法,有能人異士幫助筆者幫助解決這兩個(gè)問(wèn)題,必不勝感激!(——Florian fanzhidongyzby@163.com)
?
總結(jié)
以上是生活随笔為你收集整理的关于如何评价洗牌质量的猜想的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: POJ-2065 SETI 高斯消元,扩
- 下一篇: Android中RatingBar的自定