Leetcode之动态规划(DP)专题-877. 石子游戏(Stone Game)


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

数学题,但我们用DP来求解这一题。

我们首先定义一个类,名为P:

private static class P {
int fir, sec; P(int fir, int sec) {
this.fir = fir;
this.sec = sec;
}
}

P中有两个属性,fir代表先手获得的最高分数,sec代表后手获得的最高分数

那么我们就可以写出DP的含义

我们把dp定义为2维,如dp[i][j]代表从这堆石子的第i堆选到第j堆中获得的最高分数。

那么dp[i][j].fir 表示从第i堆到第j堆中先手获得的最高分。

dp[i][j].sec 表示从第i堆到第j堆中后手获得的最高分。

例如:piles = [5,3,4,5]

dp[0][1].fir = 5, 面对[5,3],先手可以得5分

dp[0][1].sec = 3,面对[5,3],后手可以得3分

我们首先明确一点,当 i == j 时,即只有一堆石子的时候,上面的例子,例如 i == j == 0 那么 dp[i][j].fir = 5 sec=0

所以我们把i==j时的所有情况,遍历一遍。

for (int i = 0; i < n; i++) {
dp[i][i].fir = piles[i];
dp[i][i].sec = 0;
}

下面看一张图,是最终dp数组的最后状态:

我们可以看到,dp[0][1] = (9,3)    即dp[0][1].fir = 9    sec=3

这个数值是由(0,0)和(1,1)一起生成的。

我们可以按层遍历,即:

第1层:对角线

第2层:(9,3) (9,1) (2,1)

第3层:(4,9) (10,2)

第4层:(11,4)

选择了按层遍历后,我们需要得到状态转移方程:

面对一堆石头,我们有如下情况可以选择:

1、我是先手

  • 我选左边,面对剩下的piles[i+1,j]
  • 我选右边,面对剩下的piles[i,j-1]

随后对方变成先手,我变成后手

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

2、我是后手

  • 先手选择了左边的那堆,我只能选择剩下的,dp[i][j].sec = dp[i+1][j].fir;
  • 先手选择了右边的那堆,我只能选择剩下的,dp[i][j].sec = dp[i][j-1].fir;

随后对方变成后手,我变成了先手


class Solution {
private static class P {
int fir, sec; P(int fir, int sec) {
this.fir = fir;
this.sec = sec;
}
} public boolean stoneGame(int[] piles) { int n = piles.length;
P[][] dp = new P[n + 1][n + 1];
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
dp[i][j] = new P(0, 0);
}
}
for (int i = 0; i < n; i++) {
dp[i][i].fir = piles[i];
dp[i][i].sec = 0;
} for (int c = 2; c <= n; c++) {
for (int i = 0; i <= n - c; i++) {
int j = c + i - 1;
int left = piles[i] + dp[i + 1][j].sec;
int right = piles[j] + dp[i][j - 1].sec;
if (left > right) {
dp[i][j].fir = left;
dp[i][j].sec = dp[i + 1][j].fir;
} else {
dp[i][j].fir = right;
dp[i][j].sec = dp[i][j - 1].fir;
} }
}
return dp[0][n - 1].fir > dp[0][n - 1].sec;
}
}

#本题思路来自题解区

Leetcode之动态规划(DP)专题-877. 石子游戏(Stone Game)的更多相关文章

  1. leetcode 877. 石子游戏

    题目描述: 亚历克斯和李用几堆石子在做游戏.偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] . 游戏以谁手中的石子最多来决出胜负.石子的总数是奇数,所以没有平局. 亚历克斯和李轮流进行,亚 ...

  2. 动态规划dp专题练习

    貌似开坑还挺好玩的...开一个来玩玩=v=... 正好自己dp不是很熟悉,就开个坑来练练吧...先练个50题?小目标... 好像有点多啊QAQ 既然是开坑,之前写的都不要了! 50/50 1.洛谷P3 ...

  3. [Swift]LeetCode877. 石子游戏 | Stone Game

    Alex and Lee play a game with piles of stones.  There are an even number of piles arranged in a row, ...

  4. Leetcode之动态规划(DP)专题-486. 预测赢家(Predict the Winner)

    Leetcode之动态规划(DP)专题-486. 预测赢家(Predict the Winner) 给定一个表示分数的非负整数数组. 玩家1从数组任意一端拿取一个分数,随后玩家2继续从剩余数组任意一端 ...

  5. Leetcode之动态规划(DP)专题-1025. 除数博弈(Divisor Game)

    Leetcode之动态规划(DP)专题-1025. 除数博弈(Divisor Game) 爱丽丝和鲍勃一起玩游戏,他们轮流行动.爱丽丝先手开局. 最初,黑板上有一个数字 N .在每个玩家的回合,玩家需 ...

  6. Leetcode之动态规划(DP)专题-详解983. 最低票价(Minimum Cost For Tickets)

    Leetcode之动态规划(DP)专题-983. 最低票价(Minimum Cost For Tickets) 在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行.在接下来的一年里,你要旅行的 ...

  7. Leetcode之动态规划(DP)专题-647. 回文子串(Palindromic Substrings)

    Leetcode之动态规划(DP)专题-647. 回文子串(Palindromic Substrings) 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串. 具有不同开始位置或结束位置的子 ...

  8. Leetcode之动态规划(DP)专题-474. 一和零(Ones and Zeroes)

    Leetcode之动态规划(DP)专题-474. 一和零(Ones and Zeroes) 在计算机界中,我们总是追求用有限的资源获取最大的收益. 现在,假设你分别支配着 m 个 0 和 n 个 1. ...

  9. Leetcode之动态规划(DP)专题-264. 丑数 II(Ugly Number II)

    Leetcode之动态规划(DP)专题-264. 丑数 II(Ugly Number II) 编写一个程序,找出第 n 个丑数. 丑数就是只包含质因数 2, 3, 5 的正整数. 示例: 输入: n ...

随机推荐

  1. (转)rotatelogs - Piped logging program to rotate Apache logs

    原文:http://publib.boulder.ibm.com/httpserv/manual60/programs/rotatelogs.html rotatelogs is a simple p ...

  2. Educational Codeforces Round 26 [ D. Round Subset ] [ E. Vasya's Function ] [ F. Prefix Sums ]

    PROBLEM D - Round Subset 题 OvO http://codeforces.com/contest/837/problem/D 837D 解 DP, dp[i][j]代表已经选择 ...

  3. 强制类型转换之String类型

    ㈠布尔(Boolean)类型 布尔值只有两个,主要用来做逻辑判断 true   表示真 :   false   表示假 使用typeof检查一个布尔值时,会返回boolean   ㈡Null和Unde ...

  4. K 短路

    这种东西到现在才学-- 考虑 \(T\) 为根的最短路树,一条路径一定是树上边和非树边交错. 我们只管非树边,对于一条路径,非树边构成一个序列 \(L\),相邻两条路径 \(\left(u_1,v_1 ...

  5. LOJ #2734 Luogu P3615 [JOI2016春季合宿]Toilets (结论、贪心)

    题目链接 (loj) https://loj.ac/problem/2734 (luogu) https://www.luogu.org/problem/P3615 题解 嗯,考场上肝了\(3h\)然 ...

  6. 原生Js_实现广告弹窗

    广告样式当页面加载后5s刷新在右下角 <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...

  7. hbase hbck

    Number of Tables: 7Number of live region servers: 3Number of dead region servers: 0Number of empty R ...

  8. What makes a good feature

    import numpy as np import matplotlib.pyplot as plt greyhounds = 500 # 灰猎犬500只 labs = 500 # 拉布拉多犬500只 ...

  9. PHP依赖管理工具Composer入门

    作者: JeremyWei | 可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明 网址: http://weizhifeng.net/manage-php-dependency-wi ...

  10. vue 打包部署到服务器上 配置nginx访问

    坑一 css,js资源引入不正确 webpack配置文件config/index.js 需要更改: 方法一 当部署到带有文件夹的项目中,这种绝对路径就会出现问题,因为把配置的static文件夹当成了根 ...