Pascal三角形路径求和通过折叠与基于二项式扩展的累加器

时间:2014-09-09 03:00:44

标签: haskell lazy-evaluation non-deterministic pascals-triangle

SPOILER :这是Project Euler问题#18。 自行承担风险

问题是找到"最大值"从帕斯卡三角形顶部严格向下到底部的所有非确定性路径。我试图通过在三角形的行上进行折叠来计算总和。

这是输入字符串,以及一些基本准备工作:

inputLines = ["75",
              "95 64",
              "17 47 82",
              "18 35 87 10",
              "20 04 82 47 65",
              "19 01 23 75 03 34",
              "88 02 77 73 07 63 67",
              "99 65 04 28 06 16 70 92",
              "41 41 26 56 83 40 80 70 33",
              "41 48 72 33 47 32 37 16 94 29",
              "53 71 44 65 25 43 91 52 97 51 14",
              "70 11 33 28 77 73 17 78 39 68 17 57",
              "91 71 52 38 17 14 91 43 58 50 27 29 48",
              "63 66 04 68 89 53 67 30 73 16 69 87 40 31",
              "04 62 98 27 23 09 70 98 73 93 38 53 60 04 23"]

input = map (map (read ::String ->Integer) . words) inputLines

prepareElems :: [[Integer]] -> [[Elem Integer]]
prepareElems = map mkElemsFromTri

这里有两个想法 - 有一排树,有一排三角形。我没有做很多类型级抽象,但这并不重要。这个想法是三角形中的每一行都是一个"并行枚举"其中的二项式的长度(即:[(4,0), (3,1), (2,2), ... (0,4)]),并且树的每一行都得到了#34; copy-forked"在将标记的三角形行应用于树的行之前,确保在每个机会分叉时保留非确定性的完整性。这就是我的技术:

data BiLabel = BiLabel Integer Integer
  deriving (Show, Eq)

leftLabel (BiLabel x _) = x
rightLabel (BiLabel _ y) = y

parEnumBiLabel :: Integer -> [BiLabel]
parEnumBiLabel n = map ( \x ->BiLabel x $ (n-1)-x ) [0..(n-1)]


forkBiLabel :: BiLabel -> (BiLabel, BiLabel)
forkBiLabel (BiLabel x y) = (BiLabel (x+1) y,BiLabel x (y+1))

data Elem a = Elem {label :: BiLabel, element :: a}
  deriving (Show, Eq)

forkElem :: Elem a -> [Elem a]
forkElem (Elem l a) = [Elem left a,Elem right a]
  where
    (left,right) = forkBiLabel l

-- Does a binomial expansion, but cloning the elements and making new labels
cloneNextLevel :: [Elem Integer] -> [Elem Integer]
cloneNextLevel = concatMap forkElem

我的问题是该代码适用于一行输入行,但在折叠多个行时失败。我的直觉告诉我,我的" copy-fork"技术是在我的overElems函数可以通过应用它预期有权访问的标签之前创建新标签。以下是我的主要职能:

-- this applys a 1-ary function to all Elems of a list that match the label
onLabel :: (a -> a) -> BiLabel -> [Elem a] -> [Elem a]
onLabel f (BiLabel la lb) (x:xs) | label x == BiLabel la lb = processHead : processTail
                                 | otherwise = x : processTail
   where
    processHead = Elem (BiLabel la lb) $ f (element x)
    processTail = onLabel f (BiLabel la lb) xs 
onLabel _ _ [] = []


-- this _tries_ to do the equivalent of `onLabel`, but over lists and 2-ary functions
overElems :: (a -> a -> a) -> [Elem a] -> [Elem a] -> [Elem a]
overElems f (x:xs) ys = overElems f xs ( onLabel (f $ element x) (label x) ys )
overElems _ [] ys = ys


-- This starts with the first element of `input` as an accumulator, just because
-- then I won't have to copy it over as part of the fold, and can simply 
-- `cloneNextLevel` before I process it with `overElems`.
calculate :: [[Elem Integer]] -> [Elem Integer]
calculate = foldr (\z acc -> overElems (+) z (cloneNextLevel acc)) [Elem (BiLabel 0 0) (head $ head input)]

奇怪的是折叠一行工作,但折叠多次无法应用更高阶函数,但仍然将结果扩展到正确的大小。以下是一些示例输入:

\> calculate $ prepareElems [[2,3]]

[Elem {label = BiLabel 1 0, element = 78},Elem {label = BiLabel 0 1, element = 77}]
-- that's correct, because the first element of the tree is 75

\> calculate $ prepareElems [[2,3],[10,20,30]]

[Elem {label = BiLabel 2 0, element = 75},Elem {label = BiLabel 1 1, element = 75},
Elem {label = BiLabel 1 1, element = 75},Elem {label = BiLabel 0 2, element = 75}]
-- this is the correct size and labeling, but not the right contents.

我的列表处理中的懒惰会导致这种情况吗?我的感觉是标签枚举是在overWith有机会通过标签应用函数之前发生的。这也是我的代码full page

0 个答案:

没有答案