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)
法二:观察题目,先手比赢,直接return True