Я читал о проблеме подмножеств-сумм, когда пришел к тому, что кажется алгоритмом общего назначения для его решения:
(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-полные проблемы, как правило, трудноразрешимы, и что лучшее, на что обычно можно надеяться, это эвристика, но это решение общего назначения, которое, если вы циклы процессора, всегда дают правильный ответ. Сколько других NP-полных задач можно решить, как эта?