繁体   English   中英

将一段Java代码翻译成Haskell

[英]Translating a piece of Java code to Haskell

我正在解决Baby Blocks问题。 我有一些java代码,我想将其转换为Haskell:

Java的:

for (int i = 1; i <optHeight.length ; i++) {
    int maxHeightIndex = 0;
        for (int j = i-1; j >=0 ; j--) {
            // Need help from here
            if(boxes[j].width>boxes[i-1].width && boxes[j].depth>boxes[i-1].depth) {
                if(optHeight[maxHeightIndex]<optHeight[j+1]) { <-- How do I write this condition
                    maxHeightIndex = j+1;
                }
            }
        }
        optHeight[i]=optHeight[maxHeightIndex] + boxes[i-1].height;
}

其中optHeight是一维数组,而boxes是一个以height, width, depth为数据成员的对象。 在Haskell中,它只是一个列表列表。 由于缺少可变数组/变量,我完全无能为力。

哈斯克尔:

b list = do
 forM_ [1..length list] $ \i -> do
  let maxHeight = 0
  forM_ [0..(i-1)] $ \j  -> do
   if list!!j!!1 > list!!i-1!!1 && list!!j!!2 > list !!j!!2 then
    maxHeight = j + 1

PS:我完全是Haskell的初学者

通过组合非常简单的函数来找到整体解决方案,可以以非常易读的方式解决这个问题。 可能的策略如下:

  1. 获取所有可用的块并将它们声明为初始塔。
  2. 将每个塔与每个可用块组合(如果可能)。 这导致了一组新的塔。
  3. 重复步骤2,直到塔组不再变化。
  4. 提取最高的集合塔。

相应的代码如下(以下说明):

type Block = (Int,Int,Int)
type Tower = [Block]

babyBlocks :: [Block] -> Int
babyBlocks blocks = highest $ converge allBlocks initialTowers
    where allBlocks = possibleBlocks blocks
          initialTowers = map (:[]) allBlocks

possibleBlocks :: [Block] -> [Block]
possibleBlocks = concatMap (\(w,d,h) -> [(w,d,h),(w,h,d),(d,h,w)])

canStack :: Block -> Block -> Bool
canStack (w1,d1,_) (w2,d2,_) = w2 < w1 && d2 < d1 || w2 < d1 && d2 < w1

expand :: Tower -> [Block] -> [Tower]
expand tower@(top:_) = map (:tower) . filter (canStack top)

converge :: [Block] -> [Tower] -> [Tower]
converge blocks towers | null newTowers = towers
                       | otherwise = converge blocks newTowers
    where newTowers = concatMap (flip expand blocks) towers

height :: Tower -> Int
height = sum . map (\(_,_,h) -> h)

highest :: [Tower] -> Int
highest = maximum . map height
  • babyBlocks :此函数为给定的块类型生成所有可能的块(通过旋转它们),将它们转换为初始塔组(通过将它们包装成带有一个元素的简单列表)并开始将初始塔组汇聚到最终塔中组。
  • possibleBlocks :对于给定的块类型集,此函数通过旋转它们返回所有可能的块。 严格来说,应该有3! = 6 3! = 6旋转(三个坐标的所有排列),但我们只需要考虑其中的一半,因为我们可以将交换宽度和深度的旋转视为重复。
  • canStack :检查给定块是否可以放在另一个块上。
  • expand :对于给定的塔,该功能会检查所有可用的块,如果它们可以放在塔的顶部。 为每个可以放在顶部的兼容块创建一个新塔。
  • converge :这个函数基本上重复了一组塔的expand ,直到其中一个塔不再有块。 解决方案必须是剩余塔的最大高度。
  • height :通过总计其块高来返回给定塔的高度。
  • highest :对于给定的塔组,标识最大高度。

解决这个问题的方法(我认为)是考虑每个盒子的每次旋转(所以你有3n总旋转)。 然后,您根据其基数的增加来订购这些。 那么问题就是选择彼此“适合”的盒子的最长子序列(你不必担心两次选择相同的盒子,因为盒子永远不适合自己)。 这听起来很像规范最长的子序列问题,这表明我们需要一个动态的编程解决方案。 我们将有一个长度为3n的数组,其中第i个元素表示您可以使用顶部的第i个框创建的堆栈的最大高度。

maxHeight(i) = { height(i) + max[ maxHeight(j) ] such that
                 width(j) > width(i), depth(j) > depth(i), 0 <= j < i }

现在,让我们开始使用Haskell解决方案。 我假设您的输入是维度列表。 请注意代码与我描述的解决方案有多接近 - 诀窍是以声明方式编写代码。

import Data.List (sortOn)
import Data.Vector (fromList, (!), generate)
import Data.Ord (Down(..))

babyBlocks :: [(Int,Int,Int)] -> Int
babyBlocks blocks = maxHeights ! (3*n - 1)
  where
    -- get the number of blocks
    n = length blocks

    -- generate the `3n` blocks formed by rotating the existing blocks,
    -- sort them by their base size, and store them in a vector for
    -- fast retrieval
    sortedBlocks = fromList
                 . sortOn (\(x,y,z) -> Down (x*y))
                 . concatMap (\(x,y,z) -> [(x,y,z),(y,z,x),(z,x,y)])
                 $ blocks

    -- we'll make ourselves a couple helper functions, just so
    -- our translation of the recurrence relation looks better
    height n    = let (_,_,z) = sortedBlocks ! n in z
    width n     = let (_,y,_) = sortedBlocks ! n in y
    depth n     = let (x,_,_) = sortedBlocks ! n in x
    maxHeight n = maxHeights ! n

    -- state the dynamic programming
    maxHeights = generate (3*n) (\i ->
                   height i + maximum (0 : [ maxHeight j | j<-[0..(i-1)]
                                                         , width j > width i
                                                         , depth j > depth i ]))

您似乎遇到麻烦的部分是最后一部分的动态编程。 因为Haskell是懒惰的,所以在定义maxHeights使用maxHeight实际上是完全可以的,即使我不知道我的向量将被初始化的顺序是什么!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM