zoukankan      html  css  js  c++  java
  • [LintCode] Stone Game

    There is a stone game.At the beginning of the game the player picks n piles of stones in a line.

    The goal is to merge the stones in one pile observing the following rules:

    1. At each step of the game,the player can merge two adjacent piles to a new pile.
    2. The score is the number of stones in the new pile.

    You are to determine the minimum of the total score.

    Example

    For [4, 1, 1, 4], in the best solution, the total score is 18:

    1. Merge second and third piles => [4, 2, 4], score +2
    2. Merge the first two piles => [6, 4],score +6
    3. Merge the last two piles => [10], score +10
    

    Other two examples:
    [1, 1, 1, 1] return 8
    [4, 4, 5, 9] return 43

    From the given example[4, 1, 1, 4] it looks like a greedy alogrithm of always picking two piles with smaller values

    should solve this problem. However, as most of the time that an obvious greedy alogrithm is incorrect, this time is

    no exception.

    Counter example: [6, 4, 4, 6]

    If we pick 4 + 4, score = 8, [6, 8, 6]

    then we pick 6 + 8, score = 22, [14, 6]

    finally we pick 14 + 6, score = 42.

    If we pick 6 + 4, score = 10, [10, 4, 6]

    then we pick 4 + 6 = 10, score = 20, [10, 10]

    finally we pick 10 + 10, score = 40. 

    First thought: Recursion

    for all stones A[0]....A[n - 1], we can solve this problem using the following formula.

    f(0, n - 1) = min{f(0, k) + f(k + 1, n - 1) + sum[0... n - 1]}, for all k: [0, n - 2]

    Using this formula, we can recursively solve all subproblems.

    Alert:  do we have the overlapping subproblems issue?

    Yes, we do have. 

    For example: to solve f(0, 4), we have to solve f(0, 0), f(1, 4), f(0, 1), f(2, 4), f(0, 2), f(3, 4), f(0, 3), f(4, 4)

             to solve f(0, 3), we have to solve f(0, 0), f(1, 3), f(0, 1), f(2, 3), f(0, 2), f(3, 3)

    The subproblems in red are redundantly computed. 

    So there is the all-mighty dynamic programming solution.

    State:

    dp[i][j] represents the min cost of merging A[i...j];

    Function:

    dp[i][j] = min{dp[i][k] + dp[k + 1][j] + prefixSum[j + 1] - prefixSum[i]} for all k: [i, j - 1]

    Initialization:

    dp[i][i] = 0;

    dp[i][j] = Integer.MAX_VALUE for all j > i;

    prefixSum[i]: the sum of the first ith elements of A;

    Answer:

    dp[0][A.length - 1];

    Runtime: O(n^2)   n - 1 + n - 2 + n - 3 + ...... + 1, for each fixed length len, we have n - len + 1 different start positions.

    Space: O(n^2)

    This problem is different with typical dp problems in the for-loop.

    To correctly solve this problem, we must solve all subproblems of smaller length. 

    As a result, instead of the typical for loop as shown in the following incorrect 

    solution, we need to do a for loop with subproblem's length and its start index.

    For example, in the incorrect solution, to solve dp[0][3], we need to solve

    dp[0][0], dp[1][3], dp[0][1], dp[2][3], dp[0][2], dp[3][3].

    But when trying to solve dp[0][3], i == 0, dp[1][3] and dp[2][3] have not been

    solved yet!!

    But if we first solve smaller subproblems of length 2 and 3, we can then solve 

    dp[0][3] of length 4 correctly.

    length 2: dp[0][1]  dp[2][3]

    length 3: dp[1][3]  dp[0][2]

    Incorrect bottom up dp algorithm

     1 public class Solution {
     2     public int stoneGame(int[] A) {
     3         if(A == null || A.length <= 1){
     4             return 0;
     5         }
     6         int[] prefixSum = new int[A.length + 1];
     7         for(int i = 1; i <= A.length; i++){
     8             prefixSum[i] = prefixSum[i - 1] + A[i - 1];
     9         }
    10         int[][] dp = new int[A.length][A.length];
    11         for(int i = 0; i < A.length - 1; i++){
    12             for(int j = i + 1; j < A.length; j++){
    13                 dp[i][j] = Integer.MAX_VALUE;
    14             }
    15         }
    16         for(int i = 0; i < A.length; i++){
    17             dp[i][i] = 0;
    18         }
    19         for(int i = 0; i < A.length - 1; i++){
    20             for(int j = i + 1; j < A.length; j++){
    21                 for(int k = i; k < j; k++){
    22                     dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k + 1][j] + prefixSum[j + 1] - prefixSum[i]);
    23                 }
    24             }
    25         }
    26         return dp[0][A.length - 1];
    27     }
    28 }

    Correct bottom up dp solution 

     1 public class Solution {
     2     public int stoneGame(int[] A) {
     3         if(A == null || A.length <= 1){
     4             return 0;
     5         }
     6         int[] prefixSum = new int[A.length + 1];
     7         for(int i = 1; i <= A.length; i++){
     8             prefixSum[i] = prefixSum[i - 1] + A[i - 1];
     9         }
    10         int[][] dp = new int[A.length][A.length];
    11         for(int i = 0; i < A.length - 1; i++){
    12             for(int j = i + 1; j < A.length; j++){
    13                 dp[i][j] = Integer.MAX_VALUE;
    14             }
    15         }
    16         for(int i = 0; i < A.length; i++){
    17             dp[i][i] = 0;
    18         }
    19         for(int len = 2; len <= A.length; len++){
    20             for(int start = 0; start + len - 1 < A.length; start++){
    21                 int end = start + len - 1;
    22                 for(int k = start; k < end; k++){
    23                     dp[start][end] = Math.min(dp[start][end], 
    24                                      dp[start][k] + dp[k + 1][end] + prefixSum[end + 1] - prefixSum[start]);
    25                 }
    26             }
    27         }
    28         return dp[0][A.length - 1];
    29     }
    30 }

    Related Problems

    Stone Game II

    Minimum Cost to Merge Stones (Generalized version)

  • 相关阅读:
    Java设计模式14:常用设计模式之组合模式(结构型模式)
    Android 高级UI设计笔记07:RecyclerView 的详解
    Android进阶笔记07:Android之MVC 理解
    TCP/IP协议原理与应用笔记18:构成子网和超网
    TCP/IP协议原理与应用笔记17:IP编址(重点)
    Java设计模式13:常用设计模式之桥接模式(结构型模式)
    Java设计模式12:常用设计模式之外观模式(结构型模式)
    Java设计模式11:常用设计模式之代理模式(结构型模式)
    《nginx 五》nginx实现动静分离
    《nginx 四》双机主从热备
  • 原文地址:https://www.cnblogs.com/lz87/p/6949751.html
Copyright © 2011-2022 走看看