我试图找到一个函数,给定S一组整数,我是一个整数,返回总和为I的所有S的子集
在clojure-contrib或其他库中某处有这样的功能吗?
如果不是,有人可以给我一些提示来写一下clojure方式吗?
答案 0 :(得分:3)
这不是subset sum problem,这是一个经典的NP完全问题吗?
在这种情况下,我只生成S的每个可能的不同子集,并查看哪些子集与I相加。
答案 1 :(得分:3)
我认为这是子集和问题,正如@MrBones所暗示的那样。以下是使用https://github.com/clojure/math.combinatorics(lein:[org.clojure/math.combinatorics "0.0.7"]
)的强力尝试:
(require '[clojure.math.combinatorics :as c])
(defn subset-sum [s n]
"Return all the subsets of s that sum to n."
(->> (c/subsets s)
(filter #(pos? (count %))) ; ignore empty set since (+) == 0
(filter #(= n (apply + %)))))
(def s #{1 2 45 -3 0 14 25 3 7 15})
(subset-sum s 13)
; ((1 -3 15) (2 -3 14) (0 1 -3 15) (0 2 -3 14) (1 2 3 7) (0 1 2 3 7))
(subset-sum s 0)
; ((0) (-3 3) (0 -3 3) (1 2 -3) (0 1 2 -3))
这些“子集”只是列表。可以转换回套装,但我没有打扰。
答案 2 :(得分:1)
您可以生成如下集合的子集:
(defn subsets [s]
(if (seq s)
(let [f (first s), srs (subsets (disj s f))]
(concat srs (map #(conj % f) srs)))
(list #{})))
我们的想法是从集s
中选择一个元素:第一个元素f
将会这样做。然后我们递归地找到其他所有子集srs
。 srs
包含所有没有f
的子集。通过向每个f
添加f
,我们可以获得n
的所有子集。一起,这就是很多。最后,如果我们因为没有任何元素而无法选择元素,那么唯一的子集就是空元素。
剩下要做的就是从所有子集中过滤出总和为(fn [s] (= n (reduce + s)))
的子集。测试它的功能是
(defn subsets-summing-to [s n]
(filter
(fn [xs] (= n (reduce + xs)))
(subsets s)))
不值得命名。
把这个放在一起,我们想要的功能是
concat
注释
lazy-cat
更改为map
来使其更加懒散。 {{1}}无论如何都是懒惰的。