Solving the Burst Balloon problem using Dynamic Programming

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
2
down vote

favorite
1












Continuing where I left off previously to solve the problem described here, I've now solved the same using dynamic programming (following Tikhon Jelvis blog on DP).



To refresh, the challenge is to find a sequence in which to burst a row of balloons that will earn the maximum number of coins. Each time balloon $i$ is burst, we earn $C_i-1 cdot C_i cdot C_i+1$ coins, then balloons $i-1$ and $i+1$ become adjacent to each other.



import qualified Data.Array as Array


burstDP :: [Int] -> Int
burstDP l = go 1 len
where
go left right | left <= right = maximum [ds Array.! (left, k-1)
+ ds Array.! (k+1, right)
+ b (left-1)*b k*b (right+1) | k <- [left..right]]
| otherwise = 0
len = length l
ds = Array.listArray bounds
[go m n | (m, n) <- Array.range bounds]
bounds = ((0,0), (len+1, len+1))
l' = Array.listArray (0, len-1) l
b i = if i == 0 || i == len+1 then 1 else l' Array.! (i-1)


I'm looking for:



  1. Correctness

  2. Program structure

  3. Idiomatic Haskell

  4. Any other higher order functions that can be used

  5. Other optimizations that can be done






share|improve this question





















  • This code isn't complete. What's Array?
    – Zeta
    May 24 at 17:36










  • @Zeta Data.Array imported from the array package
    – user3169543
    May 25 at 16:55
















up vote
2
down vote

favorite
1












Continuing where I left off previously to solve the problem described here, I've now solved the same using dynamic programming (following Tikhon Jelvis blog on DP).



To refresh, the challenge is to find a sequence in which to burst a row of balloons that will earn the maximum number of coins. Each time balloon $i$ is burst, we earn $C_i-1 cdot C_i cdot C_i+1$ coins, then balloons $i-1$ and $i+1$ become adjacent to each other.



import qualified Data.Array as Array


burstDP :: [Int] -> Int
burstDP l = go 1 len
where
go left right | left <= right = maximum [ds Array.! (left, k-1)
+ ds Array.! (k+1, right)
+ b (left-1)*b k*b (right+1) | k <- [left..right]]
| otherwise = 0
len = length l
ds = Array.listArray bounds
[go m n | (m, n) <- Array.range bounds]
bounds = ((0,0), (len+1, len+1))
l' = Array.listArray (0, len-1) l
b i = if i == 0 || i == len+1 then 1 else l' Array.! (i-1)


I'm looking for:



  1. Correctness

  2. Program structure

  3. Idiomatic Haskell

  4. Any other higher order functions that can be used

  5. Other optimizations that can be done






share|improve this question





















  • This code isn't complete. What's Array?
    – Zeta
    May 24 at 17:36










  • @Zeta Data.Array imported from the array package
    – user3169543
    May 25 at 16:55












up vote
2
down vote

favorite
1









up vote
2
down vote

favorite
1






1





Continuing where I left off previously to solve the problem described here, I've now solved the same using dynamic programming (following Tikhon Jelvis blog on DP).



To refresh, the challenge is to find a sequence in which to burst a row of balloons that will earn the maximum number of coins. Each time balloon $i$ is burst, we earn $C_i-1 cdot C_i cdot C_i+1$ coins, then balloons $i-1$ and $i+1$ become adjacent to each other.



import qualified Data.Array as Array


burstDP :: [Int] -> Int
burstDP l = go 1 len
where
go left right | left <= right = maximum [ds Array.! (left, k-1)
+ ds Array.! (k+1, right)
+ b (left-1)*b k*b (right+1) | k <- [left..right]]
| otherwise = 0
len = length l
ds = Array.listArray bounds
[go m n | (m, n) <- Array.range bounds]
bounds = ((0,0), (len+1, len+1))
l' = Array.listArray (0, len-1) l
b i = if i == 0 || i == len+1 then 1 else l' Array.! (i-1)


I'm looking for:



  1. Correctness

  2. Program structure

  3. Idiomatic Haskell

  4. Any other higher order functions that can be used

  5. Other optimizations that can be done






share|improve this question













Continuing where I left off previously to solve the problem described here, I've now solved the same using dynamic programming (following Tikhon Jelvis blog on DP).



To refresh, the challenge is to find a sequence in which to burst a row of balloons that will earn the maximum number of coins. Each time balloon $i$ is burst, we earn $C_i-1 cdot C_i cdot C_i+1$ coins, then balloons $i-1$ and $i+1$ become adjacent to each other.



import qualified Data.Array as Array


burstDP :: [Int] -> Int
burstDP l = go 1 len
where
go left right | left <= right = maximum [ds Array.! (left, k-1)
+ ds Array.! (k+1, right)
+ b (left-1)*b k*b (right+1) | k <- [left..right]]
| otherwise = 0
len = length l
ds = Array.listArray bounds
[go m n | (m, n) <- Array.range bounds]
bounds = ((0,0), (len+1, len+1))
l' = Array.listArray (0, len-1) l
b i = if i == 0 || i == len+1 then 1 else l' Array.! (i-1)


I'm looking for:



  1. Correctness

  2. Program structure

  3. Idiomatic Haskell

  4. Any other higher order functions that can be used

  5. Other optimizations that can be done








share|improve this question












share|improve this question




share|improve this question








edited May 27 at 9:25









Vogel612♦

20.9k345124




20.9k345124









asked May 23 at 22:23









user3169543

1604




1604











  • This code isn't complete. What's Array?
    – Zeta
    May 24 at 17:36










  • @Zeta Data.Array imported from the array package
    – user3169543
    May 25 at 16:55
















  • This code isn't complete. What's Array?
    – Zeta
    May 24 at 17:36










  • @Zeta Data.Array imported from the array package
    – user3169543
    May 25 at 16:55















This code isn't complete. What's Array?
– Zeta
May 24 at 17:36




This code isn't complete. What's Array?
– Zeta
May 24 at 17:36












@Zeta Data.Array imported from the array package
– user3169543
May 25 at 16:55




@Zeta Data.Array imported from the array package
– user3169543
May 25 at 16:55










1 Answer
1






active

oldest

votes

















up vote
0
down vote













Your use of Array for memoization can be extracted into array-memoize.



If one can stop instead of having negative balloons decrease score, go can be condensed into one case.



import Data.Function.ArrayMemoize (arrayMemoFix)
import Data.Array ((!), listArray)

burstDP :: [Int] -> Int
burstDP l = arrayMemoFix ((0,0), (len+1, len+1)) go (1, len) where
go ds (left, right) = maximum $ 0 :
[ds (left, k-1) + ds (k+1, right) + b (left-1)*b k*b (right+1) | k <- [left..right]]
b = (!) $ listArray (0, len+1) (1 : l ++ [1])
len = length l


If you don't care too much about performance, we can also memoize directly on the balloon list:



burstDP :: [Int] -> Int
burstDP = memoFix3 go 1 1 where go ds l r b = maximum
[ ds left l x + ds right x r + l*x*r
| (left, x:right) <- zip (inits b) (tails b)
]





share|improve this answer























    Your Answer




    StackExchange.ifUsing("editor", function ()
    return StackExchange.using("mathjaxEditing", function ()
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    );
    );
    , "mathjax-editing");

    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "196"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );








     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f195049%2fsolving-the-burst-balloon-problem-using-dynamic-programming%23new-answer', 'question_page');

    );

    Post as a guest






























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    0
    down vote













    Your use of Array for memoization can be extracted into array-memoize.



    If one can stop instead of having negative balloons decrease score, go can be condensed into one case.



    import Data.Function.ArrayMemoize (arrayMemoFix)
    import Data.Array ((!), listArray)

    burstDP :: [Int] -> Int
    burstDP l = arrayMemoFix ((0,0), (len+1, len+1)) go (1, len) where
    go ds (left, right) = maximum $ 0 :
    [ds (left, k-1) + ds (k+1, right) + b (left-1)*b k*b (right+1) | k <- [left..right]]
    b = (!) $ listArray (0, len+1) (1 : l ++ [1])
    len = length l


    If you don't care too much about performance, we can also memoize directly on the balloon list:



    burstDP :: [Int] -> Int
    burstDP = memoFix3 go 1 1 where go ds l r b = maximum
    [ ds left l x + ds right x r + l*x*r
    | (left, x:right) <- zip (inits b) (tails b)
    ]





    share|improve this answer



























      up vote
      0
      down vote













      Your use of Array for memoization can be extracted into array-memoize.



      If one can stop instead of having negative balloons decrease score, go can be condensed into one case.



      import Data.Function.ArrayMemoize (arrayMemoFix)
      import Data.Array ((!), listArray)

      burstDP :: [Int] -> Int
      burstDP l = arrayMemoFix ((0,0), (len+1, len+1)) go (1, len) where
      go ds (left, right) = maximum $ 0 :
      [ds (left, k-1) + ds (k+1, right) + b (left-1)*b k*b (right+1) | k <- [left..right]]
      b = (!) $ listArray (0, len+1) (1 : l ++ [1])
      len = length l


      If you don't care too much about performance, we can also memoize directly on the balloon list:



      burstDP :: [Int] -> Int
      burstDP = memoFix3 go 1 1 where go ds l r b = maximum
      [ ds left l x + ds right x r + l*x*r
      | (left, x:right) <- zip (inits b) (tails b)
      ]





      share|improve this answer

























        up vote
        0
        down vote










        up vote
        0
        down vote









        Your use of Array for memoization can be extracted into array-memoize.



        If one can stop instead of having negative balloons decrease score, go can be condensed into one case.



        import Data.Function.ArrayMemoize (arrayMemoFix)
        import Data.Array ((!), listArray)

        burstDP :: [Int] -> Int
        burstDP l = arrayMemoFix ((0,0), (len+1, len+1)) go (1, len) where
        go ds (left, right) = maximum $ 0 :
        [ds (left, k-1) + ds (k+1, right) + b (left-1)*b k*b (right+1) | k <- [left..right]]
        b = (!) $ listArray (0, len+1) (1 : l ++ [1])
        len = length l


        If you don't care too much about performance, we can also memoize directly on the balloon list:



        burstDP :: [Int] -> Int
        burstDP = memoFix3 go 1 1 where go ds l r b = maximum
        [ ds left l x + ds right x r + l*x*r
        | (left, x:right) <- zip (inits b) (tails b)
        ]





        share|improve this answer















        Your use of Array for memoization can be extracted into array-memoize.



        If one can stop instead of having negative balloons decrease score, go can be condensed into one case.



        import Data.Function.ArrayMemoize (arrayMemoFix)
        import Data.Array ((!), listArray)

        burstDP :: [Int] -> Int
        burstDP l = arrayMemoFix ((0,0), (len+1, len+1)) go (1, len) where
        go ds (left, right) = maximum $ 0 :
        [ds (left, k-1) + ds (k+1, right) + b (left-1)*b k*b (right+1) | k <- [left..right]]
        b = (!) $ listArray (0, len+1) (1 : l ++ [1])
        len = length l


        If you don't care too much about performance, we can also memoize directly on the balloon list:



        burstDP :: [Int] -> Int
        burstDP = memoFix3 go 1 1 where go ds l r b = maximum
        [ ds left l x + ds right x r + l*x*r
        | (left, x:right) <- zip (inits b) (tails b)
        ]






        share|improve this answer















        share|improve this answer



        share|improve this answer








        edited May 27 at 21:20


























        answered May 27 at 15:31









        Gurkenglas

        2,658411




        2,658411






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f195049%2fsolving-the-burst-balloon-problem-using-dynamic-programming%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            Greedy Best First Search implementation in Rust

            Function to Return a JSON Like Objects Using VBA Collections and Arrays

            C++11 CLH Lock Implementation