編程之美讀書筆記之1.11~1.13 一排石頭的遊戲

1.11 要求是N塊石頭排成一排,位置固定,A和B每次取任意一塊或者相鄰兩塊,最後取光者獲勝;使用對稱策略,先取者B先取中間的一個(奇數個)或者兩個(偶數個),然後取跟A對稱的位置相同的個數的石頭即可。先取者獲勝;


擴展問題1:條件不變,最後取光者輸。根據石頭的個數分析:1輸,2贏,3贏,4輸,5贏,6贏,接下來分析就比較麻煩了,未解決。。。


擴展問題2:一堆石頭,每人每次最多取1塊,最多取K塊,根據石頭個數確定輸贏;

若有1~k塊,先取者B贏;

若k+1塊,B輸;

若有k+2~2(k+1)塊,B贏,通過第一次取石頭,將石頭剩餘個數變爲k+1,A必輸;

同理,若有n(k+1)塊石頭,只有A保證每次取的個數爲(k+1)-B上次取的塊數,即兩次取的塊數總和爲k+1,B必輸;若有n(k+1)+m,0<m<k+1,B必贏;



*1.12 要求是N堆,每次從一堆中取若干個石頭,最後取光者獲勝。使用異或方法求解,通過分析1堆、2堆((1,1),(k,k))、n堆(1,1,1...1),若初始每堆個數的異或結果爲0,則先取者必輸;要求A每次取後能保證異或結果始終爲0;可通過一次循環,求得前n-1個較小數的異或結果,再將最大數變爲此結果求解;


擴展問題1:取光者輸;分析如上,異或結果非0,先取者B必輸,A必勝(保證每次異或結果非0);異或結果爲0,先取者必勝;


擴展問題2:每次從若干堆中取若干個石頭;,???


1.13 要求是2堆,每次從兩堆石頭中取相等的石頭,或者僅從一堆中取任意個石頭,最後取光者獲勝。固定獲勝集合。根據題目的提示,(1,2)先取者必輸,考慮到2-1=1,所有滿足(k+1,k+2)(k>0),(1,k)(此處k≠2),(2,k)(此處k>1)的情況先取者都能獲勝。然後分析差值爲2的情況,首先想到的是(3,5),此處沒有用到之前的數字1、2,分析可知先取者必輸,同理分析差值爲3且跟之前數字不重複的情況爲(4,7),以此類推,能夠獲得必輸集合中所有元素。


擴展問題1:要求給出獲勝的中間取石頭的方法。若開始情況不是必輸狀態,則通過一次取數,使得當前狀態爲必輸狀態,方法爲若初始爲(n,m)(n<m),查詢必輸集合有(n,m1),若m1<m,則取m-m1個,是當前狀態變爲(n,m1);若m1>m,計算m-n,查詢必須集合中兩數差值爲m-n的元素(n2,m2),然後n和m分別減去(n-n2)即可(此時n-n2=m-m2)。


擴展問題2:一堆石頭,第一個人不能拿光所有石頭,第一次之後每人每次最多拿對方前一次取石頭數目的2倍。

分析:n=1,不合理;

n=2=1+1,必輸;

n=3=1+2,必輸;

n=4=1+2+1,必贏;

n=5=1+f(4),必輸;

n=6=1+f(5),比贏;

...

規律,先取者第一次取數爲≤(n-1)/3;跟斐波那契數列類似,f(n)=i+f(n-i),其中0<i≤(n-1)/3;若存在f(n-i)=false,則f(n)=true;


實現代碼爲:

bool Solute(int n)
{
    if(n==1 || n==2 || n==3){
        return false;
    }

    for(int i=1 ; i<=(n-1)/3 ; i++){//note
        if(Solute(n-i) == false){
            return true;
        }
    }
    return false;
}








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章