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。