LeetCode:292 Nim遊戲 (動態規劃 / 腦筋急轉彎:巴什博弈)

題目描述

你和你的朋友,兩個人一起玩 Nim 遊戲:桌子上有一堆石頭,每次你們輪流拿掉 1 - 3 塊石頭。 拿掉最後一塊石頭的人就是獲勝者。你作爲先手。

你們是聰明人,每一步都是最優解。 編寫一個函數,來判斷你是否可以在給定石頭數量的情況下贏得遊戲。

示例:
輸入: 4
輸出: false
解釋: 如果堆中有 4 塊石頭,那麼你永遠不會贏得比賽;因爲無論你拿走 1 塊、2 塊 還是 3 塊石頭,最後一塊石頭總是會被你的朋友拿走。

來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/nim-game
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

思路 1 動態規劃

(DP會超時)
這題一眼就是DP啊,每一次只能拿1,2,3個,每一次的結果與上一次有關

狀態定義:

dp[i] 表示 先手,剩下i個石頭,能否獲勝

狀態轉移:

// 判斷自己先手的情況下,有i塊能否贏
// 問題變成對面先手,有i-1, i-2, i-3塊 能否贏
// 如果三種拿法,有一種能夠令對手不贏,自己就贏了
dp[i] = (!dp[i-1] || !dp[i-2] || !dp[i-3]);

邊界條件
一塊,兩塊,三塊的時候,先手可以直接取勝

dp[1] = true, dp[2] = true, dp[3] = true;

代碼
因爲後臺卡時間限制非常緊,即使O(n)複雜度的dp也會超時,下面會有O(1)常數複雜度的腦筋急轉彎方法

class Solution {
public:
    bool canWinNim(int n)
    {
        vector<bool> dp(n+1);
        dp[1] = true, dp[2] = true, dp[3] = true;
        for(int i=4; i<=n; i++)
            dp[i] = (!dp[i-1] || !dp[i-2] || !dp[i-3]);
        return dp[n];
    }
};

思路 2 腦筋急轉彎

這是一個【巴什博弈】問題,當 n%(m+1) != 0 時可以獲勝

如果石頭的數目是 4 的倍數,就無法取勝

證明:
已知 n=4 的情況無法取勝,因爲無論你怎麼拿,都拿不完

  • 如果石頭的數目 = 4的倍數,無論你拿多少塊(你拿了x塊),對手拿 4-x 塊,就可以使總數目 -4,最終石頭的數目會減到4,你輸掉
  • 如果石頭的數目 != 4的倍數,你可以拿 1 或 2 或 3 塊石頭,使得石堆數目變爲4的倍數,然後到對面拿,回到情況1

代碼

class Solution {
public:
    bool canWinNim(int n)
    {
        if(n%4==0)
            return false;
        return true;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章