**
《程式設計之美》一書中1.11章節介紹了nim遊戲的取勝問題。n塊石頭排成一行,每塊石頭有各自固定的位置。兩個玩家依次取石頭,每個玩家每次可以取其中任意一塊石頭,或相鄰的兩塊石頭,石頭在遊戲過程中不能移位(即編號不會改變),最後能將剩下的石頭一次取光的玩家獲勝。在這樣的規則下,先取的玩家可以在第一步取走最中間的乙個(總數為奇數時)或者兩個(總數為偶數時)石頭,然後後續過程中總取與對手取走的石頭對稱位置的相同數目的石頭。因而先取者有必勝策略。
文末的擴充套件問題部分提出乙個問題:若規定最後取光石頭的人輸,又該如何應對呢?
網上似乎也沒有這個問題的明確解法,有的給出過證明石頭總數3n+1時無法找到必勝策略其餘的則可以,但是可以看出證明過程中有明顯的漏洞,而且證明的這個3n+1的命題本來就是錯誤的……
定義s為石頭擺放的乙個格局,格局標識石頭目前的連續區段的狀態以及每個連續區段的石頭數目。初始狀態下,n塊石頭連成一體,可以表示為,即n個連續的石頭。取走第二塊石頭之後格局變成,即兩段數目分別為1和n-2的連續的石頭。
這樣,問題可以描述為:對於初始格局s_0=,甲需要找到制勝的策略。甲取完石頭將格局變為s_1後,無論乙怎麼取(記乙取完後的格局為s_2),甲總能在當前格局s_2中找到制勝的策略。問題轉化成s_2上的小乙個規模的問題。需要注意,s_2實際應為從s_1中任意取一次石頭後可能形成的眾多格局中的乙個,只要其中任意乙個s_2能讓甲無法找到制勝策略,那麼甲這次從s_0中取石頭的方法就是失敗的行不通的。依照這種思路,可以使用遞迴思路檢查甲是否能夠找到制勝的策略。
當格局中的石頭數目c較小時,可以直接檢測是否存在制勝途徑,這些條件可以作為遞迴過程中的邊界條件,如:
每一次遞迴都需要列舉所有可能的情況o(n^2),每一次列舉都需要遞迴地檢查n-2規模上的可能情況,這樣下來遞迴演算法的複雜度為o(n^n)。文末列出了未使用快取刪減分支的方法的c#的實現,使用這個方法可以在短時間內跑出n<=15的結果,但是n=16等了十幾分鐘沒出來。
遞迴過程中會出現大量的重複計算,一種思路是將當前格局的計算結果快取起來,這樣後續的計算中碰到相同的格局時只需要查表。而且,注意到格局的查詢結果和格局, 等應該是一樣的,這樣可以在計算和快取前對格局進行一致性轉換,比如將格局中連續區段按區段中包含的石頭數目的公升序進行排列,這樣也可以減少大量重複的分支計算。但是即使這樣,當n較大時,可能出現的格局總數增長也將很快(粗看也在o(n^n)的水平),這意味著結果快取空間的需求的增長也將很快,而且如何有效的索引快取空間也是乙個問題。在取得一定的時間效率增長時,空間可能又會成為問題。在石頭總數n<=32的規模下,可以使用乙個整型變數表示當前的格局(某位為1代表當前位置有石頭,否則為空),這樣可以在32位機器上使用乙個大陣列快取結果,從而將可計算規模擴充套件到32左右。
通過對拿石頭的步驟進行記錄,找到了石頭數n=7時的必勝策略,因而上文所述的網路上所說的3n+1時無法找到必勝策略是錯誤的:
先拿第2個石頭
乙拿走一塊或者兩塊石頭後,想辦法在剩餘的石頭中製造或或者的格局,可能的步驟為(<>標識我方拿石頭的方法,標識對方拿石頭的方法,只記錄前三步,因為後續即為簡單的必敗格局了):
n<16時,必勝策略存在的情況為:1×, 2√, 3√, 4×, 5√, 6√, 7√, 8√, 9×, 10√, 11√, 12×, 13√, 14√, 15√。
程式設計之美 MIN 1 一排石頭的遊戲
1.原題 1.1 題目 n塊石頭排成一行,每塊石頭有各自固定的位置。兩個玩家依次取石頭,每個玩家每次可以取其中任意一塊石頭,或者相鄰的兩塊石頭,石頭在遊戲過程中不能移位 即編號不會改變 最後能將剩下的石頭一次取光的玩家獲勝。這個遊戲有必勝策略嗎?1.2 解答 已知 石頭數量為n,假設兩個玩家分別為玩...
程式設計之美 NIM(1)一排石頭的遊戲
題目大意 n塊石頭排成一行,兩個玩家依次取石頭,每個玩家可以取其中任意一塊或者相鄰的兩塊,最後能將剩下的石頭一次取光的玩家獲勝。分析 1 n 1 n 2,必勝 2 n 3,先取者取中間1塊石頭,左右還剩下各1塊石頭,無論第二個人怎麼取,己方必勝 3 n 4,先取者取中間2塊石頭,還是左右各剩一塊,己...
程式設計之美 「拈」遊戲系列一 一排石頭的遊戲
這個題目來自於程式設計之美上的nim 1 一排石頭的遊戲,該類問題能考察面試者的思維,往往是兩個人玩的乙個遊戲,具體形式公司可以具體設定,這裡題目的意思是取石頭的數目有規定,也可以使報數每次只能增加幾個數字等。該類題目往往是要把最後乙個取完石頭定位為贏或者輸。該類題目第乙個取石頭的人占有主動權也有被...