我正在处理Project Euler's问题而我正在14th上。
我有一个可变的IOArray
来存储我已经计算过的Collatz长度:
import Data.Array.IO
import Control.Monad
import Data.Array
p14 :: IO [Int]
p14 = do
array <- p14extra
forM_ [1..1000000] $ \i -> do
e <- readArray array i
if e == 0
then do
let col = collatz i
forM_ col $ \(v,i) -> do
writeArray array i v
else return ()
frozen <- freeze array
return $ elems frozen
-- an `IOArray` from `1` to `1000000` full of `0`
p14extra :: IO (IOArray Int Int)
p14extra = newArray (1,1000000) 0
collatz :: Int -> [(Int, Int)]
collatz n
| n == 1 = [(1,1)]
| otherwise = (n, (snd $ head hack) + 1) : hack
where
hack = collatz $ if even n then (n `div` 2) else (3 * n + 1)
其中第一个元素是计算的数字,第二个数字是其Collatz序列的长度。
问题在于p14
我做writeArray array i v
但它总是有一个零(0)数组。那是为什么?
答案 0 :(得分:4)
我运行了您的确切代码,发现数组已已更改。
因为最后有很多零,所以你需要一直滚动到开头才能找到数字。
实际上,如果你替换
frozen <- freeze array
return $ elems frozen
与
sol <- getElems array
return (length . takeWhile (/=0) $ sol)
你得到525这是正确的解决方案...更多关于此的结论。
但有几个问题:
forM_ col $ \(v,i) -> do
行中,(v,i)
应该是(i,v)
,因为我从中了解到第一个值是索引,第二个值就是值。forM_ [1..10]
和newArray (1,10)
运行代码,我们会得到*** Exception: Ix{Int}.index: Index (16) out of range ((1,10))
。一旦您将值再次设置为1000000
,也会发生这种情况,因为在某些情况下,为了计算数字的标记,您必须计算大于1000000
的数字的标记。例如,837798
的标记包括仅在4个步骤后计算1885048
。试图写入该索引会破坏事情。对于第二种解决方案,您可以:
length . takeWhile (/=0) $ sol
之所以有效,是因为您使用的是(v,i)
而不是(i,v)
,因此您在索引i <中编写了最小数字,其中包含了一个折叠序列长度i / strong>,所以在索引525你有837799,然后从那里开始它全部为零,因为没有大于525的collatz序列。
答案 1 :(得分:1)
我不确定你的意思是“不会保持修改”。
使用此代码(请注意,我已经更改了迭代和数组边界):
import Control.Monad (forM_)
import Data.Array.IO
import Data.Array
p14 :: IO [Int]
p14 = do
array <- p14extra
forM_ [1..10] $ \i -> do
e <- readArray array i
if e == 0
then do
let col = collatz i
forM_ col $ \(v,i) -> do
writeArray array i v
else return ()
frozen <- freeze array
return $ elems frozen
p14extra :: IO (IOArray Int Int)
p14extra = newArray (1,100) 0
collatz :: Int -> [(Int, Int)]
collatz n
| n == 1 = [(1,1)]
| otherwise = (n, (snd $ head hack) + 1) : hack
where
hack = collatz $ if even n then (n `div` 2) else (3 * n + 1)
在p14
中运行ghci
会产生:
[1,2,4,8,16,5,10,20,40,13,26,52,17,34,11,22,7,14,28,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
答案 2 :(得分:1)
如果这令您感到困惑,那就是一种疯狂的预感:虽然p14
修改了它使用的数组,但p14extra
之后将 包含该数组。这是一个IO动作,每次运行时都会创建一个充满零的 new 数组。