当我想出一个似乎是解决它的通用算法时,我正在阅读子集和问题:
(defun subset-contains-sum (set sum)
(let ((subsets) (new-subset) (new-sum))
(dolist (element set)
(dolist (subset-sum subsets)
(setf new-subset (cons element (car subset-sum)))
(setf new-sum (+ element (cdr subset-sum)))
(if (= new-sum sum)
(return-from subset-contains-sum new-subset))
(setf subsets (cons (cons new-subset new-sum) subsets)))
(setf subsets (cons (cons element element) subsets)))))
“set”是一个不包含重复项的列表,“sum”是搜索子集的总和。“subsets”是一个 cons 单元的列表,其中“car”是一个子集列表,“cdr”是该子集的总和。只需将元素放在前面,就可以在 O(1) 时间内从旧子集创建新子集。
我不确定它的运行时复杂性是多少,但似乎随着每个元素“总和”的增长,“子集”的大小加倍,加一,所以在我看来至少是二次的。
我发布这个是因为我之前的印象是 NP 完全问题往往是棘手的,并且通常可以希望的最好的问题是启发式的,但这似乎是一个通用的解决方案,假设你有 CPU 周期,总是给你正确的答案。像这样可以解决多少其他 NP 完全问题?