Haskell的Euler 24项目

Haskell的Euler 24项目,haskell,Haskell,我试图用Haskell解决Project Euler中的问题,但我被迷住了 我试图使用阶乘来解决问题,但最后三位数字无法使用,以下是我的代码: import Data.List fact n = product [n, n-1 .. 1] recur :: Int -> Int -> [Int] -> [Int] recur x y arr | y > 1 = arr !! d : recur r (y-1) (delete (arr !! d) arr)

我试图用Haskell解决Project Euler中的问题,但我被迷住了

我试图使用阶乘来解决问题,但最后三位数字无法使用,以下是我的代码:

import Data.List
fact n = product [n, n-1 .. 1]
recur :: Int -> Int -> [Int] -> [Int]
recur x y arr
    | y > 1     = arr !! d : recur r (y-1) (delete (arr !! d) arr)
    | otherwise = arr
    where d = x `div` fact y
          r = x `mod` fact y

main::IO()
main = print(recur 1000000 9 [0..9])
(我知道它现在不是真正的“功能性”) 我设法得到了结果
[2,7,8,3,9,1,4,5,0,6]
,而我不小心手工算出的正确答案是2783915460


我只是想知道为什么这个算法在最后三位数不起作用。谢谢。

divMod
对于此算法是错误的。你需要

dvm x facty | r == 0    = (d-1, facty)
            | otherwise = (d, r)
                  where
                  (d, r) = divMod x facty
相反:

recur x y arr
.......
.......
    where (d, r) = x `dvm` fact y
我们不能有零个组合要做。零意味着没有


此外,图案保护条件应更改为
y>0
。只有当剩余选项列表的长度为1(此时
y
为0)时,才没有更多的选项可供选择,我们只使用剩下的最后一个可用数字。

未加修饰的
divMod
对于此算法是错误的。你需要

dvm x facty | r == 0    = (d-1, facty)
            | otherwise = (d, r)
                  where
                  (d, r) = divMod x facty
相反:

recur x y arr
.......
.......
    where (d, r) = x `dvm` fact y
我们不能有零个组合要做。零意味着没有


此外,图案保护条件应更改为
y>0
。只有当剩余选项列表的长度为1(此时
y
为0)时,才没有更多选项可供选择,我们只使用剩下的最后一个可用数字。

(删除(arr!!d)arr)
不是从列表中删除元素的正确方法。您是否用较小的用例测试过您的函数是否按字典顺序生成所有排列?@bipll一般来说,是的,但这里的选择列表中没有重复项,所以它是可以的。@WillNess确定的,只要“确定”的概念意味着1。取列表中的一个元素(O(d)),2。删除该元素(d比较,加上列表重建)。删除索引已知的元素真的是一种合理的方法吗?@bipll“OK”在整体正确性的意义上。(你看不到,但我也对你的评论投了更高的票。)@OP,正确的方法是使用
splitAt
(delete(arr!!d)arr)
从列表中删除元素不是正确的方法。您是否用较小的例子测试过您的函数是否按字典顺序生成所有排列?@bipll通常是的,但在选择列表中没有重复项,所以没关系。@williness当然可以,只要你的“OK”的概念意味着1。取列表中的一个元素(O(d)),2。删除该元素(d比较,加上列表重建)。删除索引已知的元素真的是一种合理的方法吗?@bipll“OK”在整体正确性的意义上。(你看不到,但我也对你的评论投了更高的票。)@OP,正确的方法是使用
splitAt
。也可以写入
dvm x facty=let(d,r)=divMod(x-1)facty in(d,r+1)
。在这种形式中,
r+1
在下一次迭代中作为
x
反馈,其中我们
divMod
x-1
,因此我们可以看到
+1
-1
相互抵消,因此,如果我们只是从
999999
开始而不是从
1000000
开始,那么可以使用普通的
divMod
,因为我们应该从
0
开始计数,而不是从
1
开始计数。也可以编写
dvm x facty=let(d,r)=divMod(x-1)facty in(d,r+1)
。在这种形式中,
r+1
在下一次迭代中作为
x
反馈,其中我们
divMod
x-1
,因此我们可以看到
+1
-1
相互抵消,因此,如果我们只是从
999999
开始而不是从
1000000
开始,那么可以使用普通的
divMod
,因为我们应该从
0
开始计数,而不是从
1
开始计数。