Haskell获得总和为X的所有数字

时间:2016-06-30 02:29:22

标签: haskell subset-sum

我需要在haskell中创建一个函数,它接收一个数字并返回一个列表列表,其中列表包含所有数字的组合,其总和是接收到的数字。

很难解释所以这是一个例子:

sum1 4 = [ [4], [3,1], [2,2], [1,3], [1,1,2], [1,2,1] , [2,1,1] ]

sum1 3 = [ [3], [2,1], [1,2], [1,1,1]

我需要使用递归和理解列表来执行此操作

修改

这是我的代码:

sum1 n = sum3 (sum2 1 (n-1) n)
sum2 x y n = if ((x+y)==n && x>0 && y>0) then [x,y]:sum2 (x+1) (y-1) n else []
sum3 [] = []
sum3 (x:xs) = sum4 x 1 : sum3 xs
sum4 [] t = []
sum4 (x:xs) t = if not (x == t) then (sum1 x) else x

是的,这是一次考试,但我不知道该怎么做

1 个答案:

答案 0 :(得分:3)

我假设这是家庭作业(而且是一个更难的IMO),所以我现在不会破坏一切。

如果您考虑一下,您应该会发现基本上有两种操作可以说明如何从汇总到xs的列表n到汇总到n+1的列表:

  • 您可以添加其他1
  • 您可以将1添加到x
  • 中的某些xs

因此,如果您设法实施这两项操作,您的任务将变得更加轻松。

第一个并不难(提示 (1:)是一个额外的1添加到某个列表的函数 - 现在你必须映射此...)

第二个有点难,虽然几乎相同的分治理念会帮助你。

以下是我将如何开始:

add1Somewhere :: Num a => [a] -> [[a]]
add1Somewhere [i] = [[i+1]]
add1Somewhere (i:is) = ???

(是的,这是部分功能)

说明:

  • 如下所示,您不必在某处插入额外的1或在x中选择任何xs - 使用第一个x xs并在第一位之前就足够了
  • 我暗示的算法有时会产生相同的结果 - 例如,如果你有一个[1,1],那么你可以稍后以两种方式结束[2,2][1,1] -> [2,1] -> [2,2][1,1] -> [1,2] -> [2,2] - 可以使用Data.List.nub删除这些内容,或者如果您更改算法以生成有序/过滤结果(不生成[1,1] -> [1,2]
  • 你的例子遗漏了[1,1,1,1]我真的无法判断这项运动是否暗示了这样的订单
  • 您可能应该查看concatMap(或concat
  • 这与@cirdec暗示的算法不同(可能是他的速度更快) - 但如果你在某个地方插入额外的1,则同样的重复问题也适用

溶液

因为它已经有一段时间了,你说这是一个旧的考试问题,我认为可以破坏它(如果你不想要的话,不要读它到)

所以这是一个可能的解决方案(不考虑任何性能问题):

import Data.List (nub)

sum1 :: (Eq a, Num a) => a -> [[a]]
sum1 1 = [[1]]
sum1 n = nub $ concatMap add1Somewhere ns ++ map (1:) ns
  where ns = sum1 (n-1)

add1Somewhere :: Num a => [a] -> [[a]]
add1Somewhere [i] = [[i+1]]
add1Somewhere (i:is) = ((i+1):is) : map (i:) (add1Somewhere is)

请注意,这会使用concatMapnub,这两者可能也可能不适合。

我希望你能得到基本的想法

明显更好的解决方案

oops - 我只是注意到你可以摆脱所有有问题的函数,例如concatnub,因为它足以只是在1前加{ {1}}或递增第一个列表元素 - 递归将提供所有需要的permations(我提到的不同路径恰好是排列) - 虽然 的顺序不同/ p>

sum1 :: (Eq a, Num a) => a -> [[a]]
sum1 1 = [[1]]
sum1 n = map add1 ns ++ map prep1 ns
  where ns          = sum1 (n-1)
        prep1 is    = 1:is
        add1 (i:is) = (i+1):is

当然,如果你想要

,你可以用列表理解来替换map

证明这可以找到所有排列

感应n(假设只有正数)

n=1注意[1]是唯一可能的列表

现在假设我们找到了n>0的所有permations并查看了一些列表xs 总计为n+1(显然列表必须非空)

现在x的第一个元素xs = x:ys将是1>1

  • x=1 - 在这种情况下,prep1将提供xs,因为我们的算法通过归纳找到了ys(请注意sum ys = sum xs - 1 = n
  • x>1 - 在这种情况下,我们的算法通过归纳找到(x-1):ysadd1将创建xs(再次因为sum ((x-1):ys) = sum xs - 1 = n