877石子游戏

题目:亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] 。游戏以谁手中的石子最多来决出胜负。石子的总数是奇数,所以没有平局。亚历克斯和李轮流进行,亚历克斯先开始。 每回合,玩家从行的开始或结束处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止,此时手中石子最多的玩家获胜。假设亚历克斯和李都发挥出最佳水平,当亚历克斯赢得比赛时返回 true ,当李赢得比赛时返回 false 。

来源:https://leetcode-cn.com/problems/stone-game/

法一:参考别人的代码写的

思路:比较典型的博弈动态规划题,关键是要用list记录每次博弈双方的状态,写出动态转移方程,dp[i][j]格式为(a,b),a表示先手的最优解,b表示后手的最优解,dp[i][j][0]等于nums[i]加dp[i+1][j][1]与nums[j]加dp[i][j-1][1]的最大值,都是加的后手,把博弈双方的状态都记录下来,逐步递推,这个题类似与区间dp,从内到外递推。

from typing import List
class Solution:
    def stoneGame(self, piles: List[int]) -> bool:
        size = len(piles)
        dp = [[0] * size for i in range(size)]
        # 添加初始条件
        for i in range(size):
            dp[i][i] = (piles[i], 0)
        # 控制列的起始值
        for start_col in range(1,size):
            row = 0
            for col in range(start_col, size):
                # 两种方法,
                # 法一,如果直接判断出了先手的最优解,则后手是总和值减去先手,
                # a = max( piles[row] + dp[row+1][col][1], piles[col] + dp[row][col-1][1])
                # b = sum(piles[row:col+1]) - a
                # dp[row][col] = (a,b)
                # 法二,对先手分两种情况,后手分别采用对应的不同策略
                left = piles[row] + dp[row+1][col][1]
                right = piles[col] + dp[row][col-1][1]
                # 如果先手取左边的大,则会取左边,则后手相当于dp[row+1][col]的先手
                if left > right:
                    b = dp[row+1][col][0]
                    dp[row][col] = (left,b)
                else:
                    b = dp[row][col-1][0]
                    dp[row][col] = (right,b)
                row += 1
        print(dp)
        return True if dp[0][-1][0] > dp[0][-1][1] else False
if __name__ == '__main__':
    duixiang = Solution()
    a = duixiang.stoneGame([3,9,1,2])
    print(a)
View Code

法二:观察题目,先手比赢,直接return True

 

posted on 2020-02-06 10:05  吃我一枪  阅读(215)  评论(0编辑  收藏  举报

导航