美文网首页动态规划
LeetCode-python 877. 石子游戏

LeetCode-python 877. 石子游戏

作者: wzNote | 来源:发表于2019-04-23 19:46 被阅读6585次

题目链接
难度: 中等       类型:动态规划


亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 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 。

解题思路


让我们改变游戏规则,使得每当李得分时,都会从亚历克斯的分数中扣除。

令 dp(i, j) 为亚历克斯可以获得的最大分数,其中剩下的堆中的石子数是 piles[i], piles[i+1], ..., piles[j]。这在比分游戏中很自然:我们想知道游戏中每个位置的值。

我们可以根据 dp[i + 1][j] 和 dp[i][j-1] 来制定 dp[i][j] 的递归,我们可以使用动态编程以不重复这个递归中的工作。(该方法可以输出正确的答案,因为状态形成一个DAG(有向无环图)。)

算法


当剩下的堆的石子数是 piles[i], piles[i+1], ..., piles[j] 时,轮到的玩家最多有 2 种行为。

可以通过比较 j-i和 N modulo 2 来找出轮到的人。

如果玩家是亚历克斯,那么她将取走 piles[i] 或 piles[j] 颗石子,增加她的分数。之后,总分为 piles[i] + dp[i+1][ j] 或 piles[j] + dp[i][ j-1];我们想要其中的最大可能得分。

如果玩家是李,那么他将取走 piles[i] 或 piles[j] 颗石子,减少亚历克斯这一数量的分数。之后,总分为 -piles[i] + dp[i+1][ j] 或 -piles[j] + dp[i][j-1];我们想要其中的最小可能得分。

另一个算法


动态规划,建立二维数组dp[N][N],其中N为piles数组长度。

  • dp[ i ][ j ]表示在piles中下标 i 至下标 j 之间的亚力克斯所拿石子总数和李所拿石子总数之差
  • dp[ i ][ j ] > 0 时亚历克斯拿的石子数目大于李,亚力克斯胜利,否则李胜利
  • dp的初始状态是 i = j 即只有一个石子堆,由于亚历克斯先拿,则 dp[ i ][ j ] = piles[ i ]
  • 当亚历克斯拿了最左边下标为 i 的石子后,亚历克斯和李的石子数之差为 piles[ i ] - dp[ i+1 ][ j ], 当亚历克斯拿了最右边下标为j的那堆石子后,亚历克斯和李的石子数之差为 piles[ j ] - dp[ i ][ j-1 ], 取其中较大者为新的最优解。
  • 动态转移方程: dp[ i ][ j ] = max( piles[ i ] - dp[ i+1 ][ j ], piles[ j ] - dp[ i ][ j-1 ])

代码实现

import numpy as np

class Solution:
    def stoneGame(self, piles):
        N = len(piles)
        dp = np.zeros((N,N)).tolist()
        for i in range(N):
            dp[i][i] = piles[i]
        for left in range(N-2, -1, -1):
            for right in range(left + 1, N):
                if (right-left) % 2 ==1:
                    dp[left][right] = max(piles[left] + dp[left+1][right],piles[right]+dp[left][right-1])
                else:
                    dp[left][right] = min(dp[left+1][right] - piles[left],dp[left][right-1]-piles[right])
        return dp[0][N-1] > 0

相关文章

  • LeetCode-python 877. 石子游戏

    题目链接难度: 中等 类型:动态规划 亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都...

  • 100天代码挑战:DAY10

    LeetCode 877. 石子游戏 亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 p...

  • LeetCode 877. 石子游戏

    1、题目 877. 石子游戏 2、题解 首先,一开始我觉得这道题目并不严谨。因为我大略感觉到先手选择的人就能赢得这...

  • Leetcode 877. 石子游戏

    题目描述 亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] 。 游戏以谁...

  • 877.石子游戏(中等)

    参考:https://labuladong.gitbook.io/algo/mu-lu-ye-2/mu-lu-ye...

  • 取石子游戏

    题目:取石子游戏思路:这道题我是没有做出来,主要是我并没有找到相应的规律,后来参考了网上的算法,说这道题是威尔佐夫...

  • 取石子游戏

    Description 有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法...

  • T877、石子游戏

    亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] 。游戏以谁手中的石子最...

  • 组合游戏略述——浅谈SG游戏的若干拓展及变形

    Anti-SG 游戏桌子上有 N 堆石子,游戏者轮流取石子。每次只能从一堆中取出任意数目的石子,但不能不取。...

  • HDU-5795 NIM游戏简单变形 [2016多校]

    经典NIM游戏的一个简单变形,游戏中有N堆石子,每次走步可以选择: 取走某堆的任意个石子(不可不取); 将石子拆分...

网友评论

    本文标题:LeetCode-python 877. 石子游戏

    本文链接:https://www.haomeiwen.com/subject/lhmbgqtx.html