[Haskell-cafe] Looking for suggestions to improve my algorithm

Sterling Clover s.clover at gmail.com
Sun Sep 2 02:48:02 EDT 2007


I played around with this for a while based on the same sort of  
algorithm and ended up with a similar solution too. It turns out the  
operations saved by keeping track of already visited nodes are more  
than outweighed by the cost of doing so. (As you can see, I still  
have the hook in my code where amCn returns the visited list that I'm  
just disregarding. Ii had initially kept a giant array of all values  
to calculate, but the cost of that was unmanageable. After that, my  
big roadblock was that I couldn't come up with a good sumDivisors  
function to save my life. I tried a number of "optimized" methods  
that combined trial division with reduction based on prime  
factorizations, but i had to either reduce the lists by checking  
divisibility again somewhere along the way, or calling nub, and  
strictness and memoization  still didn't let me produce a  
factorization in reasonable time. In the end, I ended up lifting  
yours. The only problem is that I've been staring at it for a bit and  
am not really sure how it works. I'd love an explanation.

In any case, the code of my solution follows:

amCn maxval n = amCn' (propDSum n) []
      where
      amCn' cur visitedlist  =
           if cur > maxval  || cur < n then (0,visitedlist) else
           if elem cur visitedlist then (0,visitedlist) else
           if (cur == n) then ((length visitedlist) + 1,visitedlist)  
else
           (amCn' $! (propDSum cur)) $! (cur:visitedlist)

longestAmTo maxval = longestAm' 2 (0,0) where
      longestAm' n bestFit@(chainLen,minVal) =
           if n > maxval then bestFit
           else longestAm' (n+1) $! bestFit'
           where
           (count, visited) = amCn maxval n
           bestFit' = if chainLen > count then bestFit else (count,n)

properDivisorsSum :: UArray Int Int
properDivisorsSum = accumArray (+) 1 (0,1000000)
                     $ (0,-1):[(k,factor)|
                                factor<-[2..1000000 `div` 2]
                              , k<-[2*factor,2*factor+factor..1000000] ]
propDSum n = properDivisorsSum ! n

--S

On Aug 30, 2007, at 11:33 AM, Chaddaï Fouché wrote:

> 2007/8/30, Chaddaï Fouché <chaddai.fouche at gmail.com>:
>> I managed it in 7 seconds (on 1500 MHz) with an idea close to yours
>> (but I used IntSet, not IntMap), Daniel Fisher gave you some good
>> ideas to achieve it, the real snail in this problem is the  
>> sumDivisors
>> function.
>>
> I put my final solution on the wiki, it get it done in 6s now (on a
> Pentium M 1.73Mhz).
>
> -- 
> Jedaï
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe



More information about the Haskell-Cafe mailing list