solve_leetcode/problems/
0877-stone-game.rs

1/// `f(i, j)` represents:
2/// when starting with `piles[i..=j]`,
3/// the one who starts first will get `f(i, j)` more than the other one.
4///
5/// Note that `0 ≤ i ≤ j < piles.len()` and `f(i, j)` might be negative.
6///
7/// If `i == j`, `f(i, j) = piles[i]`
8///
9/// Else,
10///
11/// ```ignore
12/// f(i, j) = max(
13///     // the player takes piles[i]
14///     piles[i] - f(i + 1, j),
15///     // the player takes piles[j]
16///     piles[j] - f(i, j - 1),
17/// )
18/// ```
19///
20/// The one who starts first will win the game if and only if `f(0, n-1) > 0`
21///
22/// Now the problem is to get `f(0, n-1)`
23pub mod dp {
24    use std::cmp::max;
25
26    pub fn solve(piles: &[i32]) -> bool {
27        let n = piles.len();
28        let mut dp = vec![-1; n * n];
29        for i in (0..n).rev() {
30            for j in i..n {
31                if i == j {
32                    dp[i * n + j] = piles[i];
33                } else {
34                    let f1 = dp[(i + 1) * n + j];
35                    let f2 = dp[i * n + j - 1];
36                    assert_ne!(f1, -1);
37                    assert_ne!(f2, -1);
38                    dp[i * n + j] = max(piles[i] - f1, piles[j] - f2);
39                }
40            }
41        }
42
43        dp[n - 1] > 0
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    #[test]
50    fn problem_0877() {
51        for solve in [
52            //
53            super::dp::solve,
54        ] {
55            for (piles, result) in [
56                //
57                (&[1][..], true),
58                (&[1, 4], true),
59                (&[5, 3, 4, 5], true),
60                (&[3, 7, 2, 3], true),
61                (&[1, 3, 1], false),
62            ] {
63                let solved = solve(piles);
64
65                assert_eq!(solved, result);
66            }
67        }
68    }
69}