English 中文(简体)
Problem detecting cyclic numbers in Haskell
原标题:
  • 时间:2009-11-15 12:54:24
  •  标签:
  • haskell

I am doing problem 61 at project Euler and came up with the following code (to test the case they give):

p3 n = n*(n+1) `div` 2
p4 n = n*n
p5 n = n*(3*n -1) `div` 2
p6 n = n*(2*n -1)
p7 n = n*(5*n -3) `div` 2
p8 n = n*(3*n -2)

x n = take 2 $ show n
x2 n = reverse $ take 2 $ reverse $ show n
pX p =  dropWhile (< 999) $ takeWhile (< 10000) [p n|n<-[1..]]

isCyclic2 (a,b,c)      = x2 b == x c && x2 c == x a && x2 a == x b
ns2 = [(a,b,c)|a <- pX p3 , b <- pX p4 , c <- pX p5 , isCyclic2 (a,b,c)]

And all ns2 does is return an empty list, yet cyclic2 with the arguments given as the example in the question, yet the series doesn t come up in the solution. The problem must lie in the list comprehension ns2 but I can t see where, what have I done wrong?

Also, how can I make it so that the pX only gets the pX (n) up to the pX used in the previous pX?

PS: in case you thought I completely missed the problem, I will get my final solution with this:

isCyclic (a,b,c,d,e,f) = x2 a == x b && x2 b == x c && x2 c == x d && x2 d == x e && x2 e == x f && x2 f == x a
ns = [[a,b,c,d,e,f]|a <- pX p3 , b <- pX p4 , c <- pX p5 , d <- pX p6 , e <- pX p7 , f <- pX p8 ,isCyclic (a,b,c,d,e,f)]
answer = sum $ head ns
最佳回答

If I understand you right here, you re no longer asking why your code doesn t work but how to make it faster. That s actually the whole fun of Project Euler to find an efficient way to solve the problems, so proceed with care and first try to think of reducing your search space yourself. I suggest you let Haskell print out the three lists pX p3, pX p4, pX p5 and see how you d go about looking for a cycle.

If you would proceed like your list comprehension, you d start with the first element of each list, 1035, 1024, 1080. I m pretty sure you would stop right after picking 1035 and 1024 and not test for cycles with any value from P5, let alone try all the permutations of the combinations involving these two numbers.

(I haven t actually worked on this problem yet, so this is how I would go about speeding it up. There may be some math wizardry out there that s even faster)

First, start looking at the numbers you get from pX. You can drop more than those. For example, P3 contains 6105 - there s no way you re going to find a number in the other sets starting with 05 . So you can also drop those numbers where the number modulo 100 is less than 10.

Then (for the case of 3 sets), we can sometimes see after drawing two numbers that there can t be any number in the last set that will give you a cycle, no matter how you permutate (e.g. 1035 from P3 and 3136 from P4 - there can t be a cycle here).

I d probably try to build a chain by starting with the elements from one list, one by one, and for each element, find the elements from the remaining lists that are valid successors. For those that you ve found, continue trying to find the next chain element from the remaining lists. When you ve built a chain with one number from every list, you just have to check if the last two digits of the last number match the first two digits of the first number.

Note when looking for successors, you again don t have to traverse the entire lists. If you re looking for a successor to 3015 from P5, for example, you can stop when you hit a number that s 1600 or larger.

If that s too slow still, you could transform the lists other than the first one to maps where the map key is the first two digits and the associated values are lists of numbers that start with those digits. Saves you from going through the lists from the start again and again.

I hope this helps a bit.

问题回答

The order is important. The cyclic numbers in the question are 8128, 2882, 8281, and these are not P3/127, P4/91, P5/44 but P3/127, P5/44, P4/91.

Your code is only checking in the order 8128, 8281, 2882, which is not cyclic.

You would get the result if you check for

isCyclic2 (a,c,b)

in your list comprehension.

EDIT: Wrong Problem! I assumed you were talking about the circular number problem, Sorry!

There is a more efficient way to do this with something like this: take (2 * l x -1) . cycle $ show x where l = length . show

Try that and see where it gets you.

btw, I sense some repetition in your code.

you can unite your [p3, p4, p5, p6, p7, p8] functions into one function that will take the 3 from the p3 as a parameter etc.

to find what the pattern is, you can make all the functions in the form of

pX n = ... `div` 2




相关问题
Euler Problem in Haskell -- Can Someone Spot My Error

I m trying my hand at Euler Problem 4 in Haskell. It asks for that largest palindrome formed by multiplying two three-digit numbers. The problem was simple enough, and I thought my Haskell-fu was up ...

How does foldr work?

Can anybody explain how does foldr work? Take these examples: Prelude> foldr (-) 54 [10, 11] 53 Prelude> foldr (x y -> (x+y)/2) 54 [12, 4, 10, 6] 12.0 I am confused about these executions....

Efficient queue in Haskell

How can I efficiently implement a list data structure where I can have 2 views to the head and end of the list, that always point to a head a tail of a list without expensive calls to reverse. i.e: ...

Problem detecting cyclic numbers in Haskell

I am doing problem 61 at project Euler and came up with the following code (to test the case they give): p3 n = n*(n+1) `div` 2 p4 n = n*n p5 n = n*(3*n -1) `div` 2 p6 n = n*(2*n -1) p7 n = n*(5*n -3)...

Ways to get the middle of a list in Haskell?

I ve just started learning about Functional Programming, using Haskel. I m slowly getting through Erik Meijer s lectures on Channel 9 (I ve watched the first 4 so far) and in the 4th video Erik ...

haskell grouping problem

group :: Ord a => [(a, [b])] -> [(a, [b])] I want to look up all pairs that have the same fst, and merge them, by appending all the list of bs together where they have the same a and discarding ...

Closest equivalent to subprocess.communicate in Haskell

I want to do a popen() / python s subprocess.communicate from Haskell - start a program, give it stdin, and get its stdout/stderr. What s the most direct / Haskellish way to do this?

热门标签