(力扣---动态规划)石子游戏

本文深入探讨了力扣上的石子游戏题目,通过动态规划的方法分析了如何在偶数堆石子游戏中,让亚历克斯在与李的对决中获胜。文章详细解释了通过计算差值来确定最终胜者的策略,并提供了Python和C++的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(力扣—动态规划)石子游戏

描述

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

提示:
2 <= piles.length <= 500
piles.length 是偶数。
1 <= piles[i] <= 500
sum(piles) 是奇数。

思想1

直接return true

两个人都发挥最好 还是偶数堆 那第一个人必定有优势

思想2

如果直接return true那可能就有点投机取巧了
毕竟还是要做一下的

在动态规划中 碰到有关两者求最大最小的其实有一种常用的做法就是,不分别求出来 而是求差,然后最后一项是正的或负的分别代表不同结果

在我之前的博客中说过 算法是服务于解决问题的,不要纠结于怎么用某类算法去解决某个问题,也就是说 不要套模板
这道题要想保存差的话显然要用到一个二维数组
值得提前说一下的是 i - j为奇数的时候为亚历克斯选择,反之为李选择
亚历克斯的目的就是要从李的运算中加上相应堆取最大
李的目的就是要从压力克斯的运算中减去相应堆取最小
这就是对应的dp思想

python code
class Solution:
    def stoneGame(self, piles: List[int]) -> bool:
        dp = [[0 for i in piles] for i in piles]                        # 初始化dp数组
        def cal(i: int, j: int):
            'i代表左边界 j代表右边界'
            if dp[i][j]:
                return dp[i][j]
            elif i + 1 == j:
                return max(piles[i], piles[j])
            else:
                if (j - i) % 2:                                         # 轮到压力克斯选
                    dp[i][j] = max(cal(i + 1, j) + piles[i], cal(i, j - 1) + piles[j])
                else:                                                   # 轮到李选
                    dp[i][j] = min(cal(i + 1, j) - piles[i], cal(i, j - 1) - piles[j])
                return dp[i][j]
        cal(0, len(piles) - 1)
        return True if dp[0][len(piles) - 1] else False
c++ code
class Solution {
public:
    int CacuDiffer(vector<int>& piles, vector<vector<int>>& dp, int i, int j){
        if(dp[i][j]) return dp[i][j];                                           //dp[i][j]有数据直接返回
        else if(i + 1 == j){                                                    //只有两堆的时候
            dp[i][j] = max(piles[i], piles[j]);
            return dp[i][j];
        }
        else{  
            if((j - i) % 2)                                                     //当是ya在选择的时候
                dp[i][j] = max(CacuDiffer(piles, dp, i + 1, j) + piles[i], CacuDiffer(piles, dp, i, j - 1) + piles[j]);
            else
                dp[i][j] = min(CacuDiffer(piles, dp, i + 1, j) - piles[i], CacuDiffer(piles, dp, i, j - 1) - piles[j]);
            return dp[i][j];
        }
    }
    
    bool stoneGame(vector<int>& piles) {
        vector<vector<int>> dp(piles.size(), vector<int>(piles.size()));        //动归数组,记录差值
        CacuDiffer(piles, dp, 0, piles.size() - 1);
        return dp[0][piles.size() - 1] > 0 ? true : false;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值