Leetcode(877)-石子游戲


亞歷克斯和李用幾堆石子在做游戲。偶數堆石子排成一行,每堆都有正整數顆石子 piles[i] 。

游戲以誰手中的石子最多來決出勝負。石子的總數是奇數,所以沒有平局。

亞歷克斯和李輪流進行,亞歷克斯先開始。 每回合,玩家從行的開始或結束處取走整堆石頭。 這種情況一直持續到沒有更多的石子堆為止,此時手中石子最多的玩家獲勝。

假設亞歷克斯和李都發揮出最佳水平,當亞歷克斯贏得比賽時返回 true ,當李贏得比賽時返回 false 。 

示例:

輸入:[5,3,4,5]
輸出:true
解釋:
亞歷克斯先開始,只能拿前 5 顆或后 5 顆石子 。
假設他取了前 5 顆,這一行就變成了 [3,4,5] 。
如果李拿走前 3 顆,那么剩下的是 [4,5],亞歷克斯拿走后 5 顆贏得 10 分。
如果李拿走后 5 顆,那么剩下的是 [3,4],亞歷克斯拿走后 4 顆贏得 9 分。
這表明,取前 5 顆石子對亞歷克斯來說是一個勝利的舉動,所以我們返回 true 。 

提示:

  1. 2 <= piles.length <= 500
  2. piles.length 是偶數。
  3. 1 <= piles[i] <= 500
  4. sum(piles) 是奇數。

思路:其實這道題出的並不好。因為只有偶數堆的石子,對於第一個取石子的人來說,每次他都會取的比第二個的人取得多(至少不會少),所以直接返回true,就可以AC。

但是知道出題人的本意不是如此,所以我們討論下這道題的其他解法。可以用動態規划來解。dp[i][j]代表數組下標從i到j的數組中做游戲,玩家1比玩家2多出的石子數。那么對於dp[i][i]來說,就是只有一堆石子可供選擇,自然是piles[i]本身。dp[i][j]的轉化方程可以理解為從dp[i+1][j]和dp[i][j-1]來得到。

dp[i][j]=max(piles[i]-dp[i+1][j],piles[j]-dp[i][j-1]);

可能這里的piles[i]-dp[i+1][j]減法不是很好理解。是因為如果玩家1選擇了piles[i],那么玩家2就要從i+1到j的數組中做出選擇,玩家2的選擇遵循最多的原則,dp[i+1][j]代表的是玩家1比玩家2多的石子數,那么這個時候玩家2可以把自己當玩家1這么選擇,是最好的選擇方式。所以這里要對於玩家1來說,相當於玩家2偷學了自己的選擇方式,得到了分數,對自己來說是負分數。

bool stoneGame(vector<int>& piles) 
{
        int len = piles.size();
        vector<vector<int> >dp;
        dp.resize(len, vector<int>(len));
        for(int i=0;i<len;i++)
            dp[i][i]=piles[i];
        for(int l=2;l<=len;l++)
            for(int i=0;i<=len-l;i++)
            {
                int j=i+l-1;
                dp[i][j]=max(piles[i]-dp[i+1][j],piles[j]-dp[i][j-1]);
            }
        return dp[0][len-1]>0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM