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];
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章