• Leetcode(877)-石子游戏


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

    提示:

    1. 2 <= piles.length <= 500
    2. piles.length 是偶数。
    3. 1 <= piles[i] <= 500
    4. sum(piles) 是奇数。

    思路:其实这道题出的并不好。因为只有偶数堆的石子,对于第一个取石子的人来说,每次他都会取的比第二个的人取得多(至少不会少),所以直接返回true,就可以AC。

    但是知道出题人的本意不是如此,所以我们讨论下这道题的其他解法。可以用动态规划来解。dp[i][j]代表数组下标从i到j的数组中做游戏,玩家1比玩家2多出的石子数。那么对于dp[i][i]来说,就是只有一堆石子可供选择,自然是piles[i]本身。dp[i][j]的转化方程可以理解为从dp[i+1][j]和dp[i][j-1]来得到。

    dp[i][j]=max(piles[i]-dp[i+1][j],piles[j]-dp[i][j-1]);

    可能这里的piles[i]-dp[i+1][j]减法不是很好理解。是因为如果玩家1选择了piles[i],那么玩家2就要从i+1到j的数组中做出选择,玩家2的选择遵循最多的原则,dp[i+1][j]代表的是玩家1比玩家2多的石子数,那么这个时候玩家2可以把自己当玩家1这么选择,是最好的选择方式。所以这里要对于玩家1来说,相当于玩家2偷学了自己的选择方式,得到了分数,对自己来说是负分数。

    bool stoneGame(vector<int>& piles) 
    {
            int len = piles.size();
            vector<vector<int> >dp;
            dp.resize(len, vector<int>(len));
            for(int i=0;i<len;i++)
                dp[i][i]=piles[i];
            for(int l=2;l<=len;l++)
                for(int i=0;i<=len-l;i++)
                {
                    int j=i+l-1;
                    dp[i][j]=max(piles[i]-dp[i+1][j],piles[j]-dp[i][j-1]);
                }
            return dp[0][len-1]>0;
    }
  • 相关阅读:
    Git常用
    自学过程
    SpringJunitTest
    通过Maven更换环境配置文件
    MongDB的DateZone
    工具使用问题
    项目中遇到的关于Java的问题
    iTerm2使用Profiles自动登录
    脚本:将git项目下载到本地并启动
    一些新的认识
  • 原文地址:https://www.cnblogs.com/mini-coconut/p/9387749.html
Copyright © 2020-2023  润新知