1. 程式人生 > >智力題 (一)Nim遊戲

智力題 (一)Nim遊戲

Nim遊戲是博弈論中最經典的模型(之一),它又有著十分簡單的規則和無比優美的結論 Nim遊戲是組合遊戲(Combinatorial Games)的一種,準確來說,屬於“Impartial Combinatorial Games”(以下簡稱ICG)。

滿足以下條件的遊戲是ICG(可能不太嚴謹):

1、有兩名選手;

2、兩名選手交替對遊戲進行移動(move),每次一步,選手可以在(一般而言)有限的合法移動集合中任選一種進行移動;

3、對於遊戲的任何一種可能的局面,合法的移動集合只取決於這個局面本身,不取決於輪到哪名選手操作、以前的任何操作、骰子的點數或者其它什麼因素;

4、如果輪到某名選手移動,且這個局面的合法的移動集合為空(也就是說此時無法進行移動),則這名選手負。

根據這個定義,很多日常的遊戲並非ICG。

例如象棋就不滿足條件3,因為紅方只能移動紅子,黑方只能移動黑子,合法的移動集合取決於輪到哪名選手操作。

通常的Nim遊戲的定義是這樣的:

有若干堆石子,每堆石子的數量都是有限的,合法的移動是“選擇一堆石子並拿走若干顆(不能不拿)”,

如果輪到某個人時所有的石子堆都已經被拿空了,則判負(因為他此刻沒有任何合法的移動)。

這遊戲看上去有點複雜,先從簡單情況開始研究吧。

決勝策略

1.如果輪到你的時候,只剩下一堆石子,那麼此時的必勝策略肯定是把這堆石子全部拿完一顆也不給對手剩,然後對手就輸了。

2.如果剩下兩堆不相等的石子,必勝策略是通過取多的一堆的石子將兩堆石子變得相等,

以後如果對手在某一堆裡拿若干顆,你就可以在另一堆中拿同樣多的顆數,直至勝利。

3.如果你面對的是兩堆相等的石子,那麼此時你是沒有任何必勝策略的,反而對手可以遵循上面的策略保證必勝。

如果是三堆石子……好像已經很難分析了,看來我們必須要藉助一些其它好用的(最好是程式化的)分析方法了,

或者說,我們最好能夠設計出一種在有必勝策略時就能找到必勝策略的演算法。

定義P-position和N-position,其中P代表Previous,N代表Next。
直觀的說,上一次move的人有必勝策略的局面是P-position,也就是“後手可保證必勝”或者“先手必敗”,
現在輪到move的人有必勝策略的局面是N-position,也就是“先手可保證必勝”。

更嚴謹的定義是:
1.無法進行任何移動的局面(也就是terminal position)是P-position;
2.可以移動到P-position的局面是N-position;
3.所有移動都導致N-position的局面是P-position。
按照這個定義,如果局面不可能重現,或者說positions的集合可以進行
拓撲排序

那麼每個position或者是P-position或者是N-position,而且可以通過定義計算出來。

以Nim遊戲為例來進行一下計算。

比如說我剛才說當只有兩堆石子且兩堆石子數量相等時後手有必勝策略,也就是這是一個P-position,

下面我們依靠定義證明一下(3,3)是一個P-position。

首先(3,3)的子局面(也就是通過合法移動可以導致的局面)有(0,3)(1,3)(2,3)
(顯然交換石子堆的位置不影響其性質,所以把(x,y)和(y,x)看成同一種局面),只需要計算出這三種局面的性質就可以了。

(0,3)的子局面有(0,0)、(0,1)、(0,2),其中(0,0)顯然是P-position,所以(0,3)是N-position(只要找到一個是P-position的子局面就能說明是N-position)。
(1,3)的後繼中(1,1)是P-position(因為(1,1)的唯一子局面(0,1)是N-position),所以(1,3)也是N-position。
同樣可以證明(2,3)是N-position。所以(3,3)的所有子局面都是N-position,它就是P-position。

通過一點簡單的數學歸納,可以嚴格的證明“有兩堆石子時的局面是P-position當且僅當這兩堆石子的數目相等”。

根據上面這個過程,可以得到一個遞迴的演算法——對於當前的局面,遞迴計算它的所有子局面的性質,

如果存在某個子局面是P-position,那麼向這個子局面的移動就是必勝策略。

當然,可能你已經敏銳地看出有大量的重疊子問題,所以可以用DP或者記憶化搜尋的方法以提高效率。

但問題是,利用這個演算法,對於某個Nim遊戲的局面(a1,a2,...,an)來說,要想判斷它的性質以及找出必勝策略,需要計算O(a1*a2*...*an)個局面的性質,不管怎樣記憶化都無法降低這個時間複雜度。所以我們需要更高效的判斷Nim遊戲的局面的性質的方法。

(Bouton's Theorem)對於一個Nim遊戲的局面(a1,a2,...,an),
它是P-position當且僅當a1^a2^...^an=0,其中^表示異或(xor)運算。

怎麼樣,是不是很神奇?
我看到它的時候也覺得很神奇,完全沒有道理的和異或運算扯上了關係。
但這個定理的證明卻也不復雜,基本上就是按照兩種position的證明來的。

根據定義,證明一種判斷position的性質的方法的正確性,只需證明三個命題:
1、這個判斷將所有terminal position判為P-position;
2、根據這個判斷被判為N-position的局面一定可以移動到某個P-position;
3、根據這個判斷被判為P-position的局面無法移動到某個P-position。

第一個命題顯然,terminal position只有一個,就是全0,異或仍然是0。第二個命題,對於某個局面(a1,a2,...,an),若a1^a2^...^an<>0,一定存在某個合法的移動,將ai改變成ai'後滿足a1^a2^...^ai'^...^an=0。不妨設a1^a2^...^an=k,則一定存在某個ai,它的二進位制表示在k的最高位上是1(否則k的最高位那個1是怎麼得到的)。這時ai^k<ai一定成立。則我們可以將ai改變成ai'=ai^k,此時a1^a2^...^ai'^...^an=a1^a2^...^an^k=0。第三個命題,對於某個局面(a1,a2,...,an),若a1^a2^...^an=0,一定不存在某個合法的移動,將ai改變成ai'後滿足a1^a2^...^ai'^...^an=0。因為異或運算滿足消去率,由a1^a2^...^an=a1^a2^...^ai'^...^an可以得到ai=ai'。所以將ai改變成ai'不是一個合法的移動。證畢。

根據這個定理,我們可以在O(n)的時間內判斷一個Nim的局面的性質,且如果它是N-position,也可以在O(n)的時間內找到所有的必勝策略。Nim問題就這樣基本上完美的解決了。
百度的描述 感覺是sb


一道程式設計題

    #include<stdio.h>  
    int main()  
    {  
        int n,temp,ans;  
        while(scanf("%d",&n)!=EOF)  
        {  
            scanf("%d",&ans);  
            for(int i=1;i<n;i++){  
                scanf("%d",&temp);  
                ans^=temp;  
            }  
            puts(ans==0?"B":"A");  
        }  
        return 0;  
    }  



相關推薦

智力 Nim遊戲

Nim遊戲是博弈論中最經典的模型(之一),它又有著十分簡單的規則和無比優美的結論 Nim遊戲是組合遊戲(Combinatorial Games)的一種,準確來說,屬於“Impartial Combinatorial Games”(以下簡稱ICG)。滿足以下條件的遊戲是ICG(

【整理自用】清奇思路NIM遊戲堆石頭,最後一個勝利

NIM遊戲類似 一共有N堆石子,編號1..n,第i堆中有個a[i]個石子。每一次操作Alice和Bob可以從任意一堆石子中取出任意數量的石子,至少取一顆,至多取出這一堆剩下的所有石子。兩個人輪流行動,取走最後一個的人勝利。Alice為先手。 招

【雷電】源代碼分析-- 進入遊戲開始界面

模式 show 源代碼下載 popu 按鍵事件 file fcm md5 顯示 轉載請註明出處:http://blog.csdn.net/oyangyufu/article/details/24941949 源代碼下載:http://download.csdn.n

Java 刷

tinc abc 不同的 bsp for take collect long 區別 Codewars 刷題第一天,字符串問題: 題目: Take 2 strings s1 and s2 including only letters from ato z.

【微信小遊戲遊戲開發調試--關於找不到app.json入口文件

com png info alt 微信開發者 遊戲 進入 http 找不到 經了解發現 小程序必須要有app.json 小遊戲必須的文件只有2個 game.js  小遊戲入口文件 game.json  小遊戲配置文件 所以不是工程文件缺失,解決方案如下: 進入微信開發者工具

Python 二級模擬操作

中國 正方 range 進制數 存儲 字符 light 包含 pri 1.計算下列式子,結果保留小數點後保留3位 代碼: >>> x = pow((3**4 + 5*(6**7))/8, 0.5) >>> print("%.

劍指offer演算法二維陣列中的查詢

劍指offer演算法題(一) 題目1:二維陣列中的查詢 在一個二維陣列中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。 思路分析:  從左上往右下方來解決這個問題  例如在

【精選】JAVA入門演算法

跌倒了,一定要爬起來。不爬起來,別人會看不起你,你也會失去機會。 1.題目:打印出楊輝三角形(要求打印出10行) 什麼是楊輝三角呢?下面這個就是 楊輝三角最大的特性就是每個數字都是該數字肩上的兩個數字之和,這道題經常在學習二維陣列和迴圈控制中出現 我們可以假設

演算法十八:搜狗19年校招程式設計——找區間

注:筆試時並沒有AC,線下修改後可以輸出示例結果。 問題:從一個序列中找出所有包含全部數字的最小索引區間,若有多個則按出現的順序輸出。 輸入輸出示例: 輸入:1 1 3 4 6 6 5 1 1 3 3 輸出:[2,7] [3,8] [4,9] 分析:先用一個list

python 二級考試操作

一、參照程式碼模板完善程式碼,實現下述功能。從鍵盤輸入一個整數和一個字元,以逗號隔開,在螢幕上顯示輸出一條資訊。 —————————————————————————————– 示例如下: 輸入:10,@ 輸出:@@@@@@@@@@ 10 @@@@@

java面試每日十

1、面向物件的特徵有哪些方面? 答:抽象、封裝、繼承和多型。 抽象:抽象就是忽略一個主題中與當前目標無關的那些方面,以便更充分地注意與當前目標有關的方面。抽象並不打算了解全部問題,而只是選擇其中的一

演算法趣

1. 迴文十進位制數 問題描述:求十進位制、二進位制、八進位制表示都是迴文數的所有數字中,大於10的最小數值。例如:9(十進位制數)= 1001(二進位制數)= 11(八進位制數),這樣的數字,但要找到

python3 每日十

'''1 列表[1,3,5,7,9],請將之拼接為一個字串''' print(''.join([str(i) for i in [1,3,5,7,9] ])) '''2 將"13579"的字串轉換為一個列表''' a_list = [] for i in "13579

牛客網刷 從尾到頭列印連結串列

  輸入一個連結串列,按連結串列值從尾到頭的順序返回一個ArrayList。 class Solution { public: vector<int> printListFromTailToHead(ListNode* head) { s

牛客網刷型別轉換

目錄 一:布林值轉換:  ([])?ture:false; 給出如上程式碼,判斷輸出‘ 有一下特例轉換為false,其它均轉化為true; 1)string:''轉化為false 2)number:0轉化為false 3)物件:  為null時,轉化為

Python面試3小

一、Python中賦值,淺拷貝和深拷貝的區別? 參考部落格:https://www.cnblogs.com/xueli/p/4952063.html 1、賦值 在python中,物件賦值實際上是物件的引用。當建立一個物件,然後把它賦給另一個變數的時候,python並沒有拷貝這個物件,而只是拷

Python 入門程式設計答案

Python 入門程式設計題:1~10(答案) 提示:最好還是先思考,先編寫,再看答案哦 ^_^ 1. for i in range(1, 5): for j in range(1,5): for k in range(1, 5): if i != j and j!= k

Python 入門程式設計

Python 入門程式設計題:1~10 本系列部落格都是一些比較簡單的題目,適合新手,因為我就是新手~非常歡迎大家一起討論,讓我們一起進步! 1、題目:有四個數字:1、2、3、4,能組成多少個互不相同且無重複數字的三位數?各是多少? 程式分析:可填在百位、十位、個位的數字都是

java面試12

java面試12題(一) 文章目錄 java面試12題(一) 1. 為什麼java被稱作“平臺無關的程式語言”? 2. 什麼是java虛擬機器(JVM)? 3.JDK和JRE的區別 4. static關鍵字

華為機試程式設計

        2019年華為校園招聘已經開啟,筆試也在如火如荼的進行中,研發崗位的小夥伴們免不了要參加華為的機試,那麼小編就來分享一下往年華為機試的題目。 1、字串最後一個單詞的長度 題目描述:計算字串最後一個單詞的長度,單詞以空格隔開 輸入描述:一行字串,非空,長度