leetcode:石子游戲

題目來源:力扣

題目介紹:

亞歷克斯和李用幾堆石子在做遊戲。偶數堆石子排成一行,每堆都有正整數顆石子 piles[i] 。
遊戲以誰手中的石子最多來決出勝負。石子的總數是奇數,所以沒有平局。
亞歷克斯和李輪流進行,亞歷克斯先開始。 每回合,玩家從行的開始或結束處取走整堆石頭。 這種情況一直持續到沒有更多的石子堆爲止,此時手中石子最多的玩家獲勝。
假設亞歷克斯和李都發揮出最佳水平,當亞歷克斯贏得比賽時返回 true ,當李贏得比賽時
返回 false 。

由於題目中石子爲偶數堆,因此在玩家均發揮最佳水平時,先手總是會贏得勝利.參照一份精彩的題解,我們將此題做修改,在任意整數堆情況下進行遊戲,判斷先手能否取得最終勝利.

審題:

  • 確定狀態
    首先,我們考慮當前動態規劃過程中的任一步的狀態.對於該問題,很容易確定的一個狀態是當前所剩石子.由於在每一步中用戶僅能取第一堆或最後一堆,因此當前所剩的石堆是連續的,我們可以使用起始堆編號與結束堆編號描述當前的石堆狀態.由於該問題爲雙人博弈遊戲,因此另一遊戲狀態爲當前正在走步的用戶.我們可以使用三個狀態變量描述當前遊戲狀態.

  • 確定狀態轉移方程
    使用S[i][j][0]表示在當前所剩石堆爲石堆[i,j]時,正在走步的用戶所能夠獲得的最多石子個數.S[i][j][1]表示在當前所剩石堆爲石堆[i, j]時,當前處於等待狀態的用戶所能獲得的最多石子個數.我們可以推導出如下狀態轉移方程:

S[i][j][0] = Math.max(piles[i] + S[i+1][j][1], piles[j] + S[i][j-1][1]) 
//對於走步用戶,其在下一狀態爲等待.

//等待用戶在下一狀態成爲走步用戶
if(走步用戶選擇了左側堆)
	S[i][j][1] = S[i+1][j][0];
else
	S[i][j][1] = S[i][j-1][0];
  • 確定基準狀態
    對於該問題,如果當前所剩石堆僅有一堆,則S[i][i][0] = piles[0], S[i][i][1] = 0;
    走步用戶取走該石堆,等待用戶無石堆可取.

基於以上分析,S[0][piles.length-1][0]表示先手用戶最終能獲得的最多石子個數,S[0][piles.length-1][1]表示後手用戶最終能獲得的最多石子個數.

java代碼

class Solution {
    public boolean stoneGame(int[] piles) {
        int[][][] S = new int[piles.length][piles.length][2];
        //如果只剩一堆
        for(int i = 0; i < piles.length; i++){
            S[i][i][0] = piles[i];
            S[i][i][1] = 0;
        }

        for(int len = 2; len <= piles.length; len++){
            for(int l = 0; l <= piles.length-len; l++){
    
                int r = l + len - 1;
				//判斷當前走步用戶的兩種不同選擇
                int left = piles[l] + S[l+1][r][1];
                int right = piles[r] + S[l][r-1][1];
                if(left > right){
                    S[l][r][0] = left; 
                    S[l][r][1] = S[l+1][r][0];
                }
                else{
                    S[l][r][0] = right;
                    S[l][r][1] = S[l][r-1][0];
                }   
            }
        }
        return S[0][piles.length-1][0] > S[0][piles.length-1][1];
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章