【发布时间】:2014-07-30 03:18:10
【问题描述】:
我正在尝试使用 Common Lisp 以蛮力方式解决 this。用于教育和娱乐目的。
这是代码
(defparameter +items+
'((:mixed-fruit 215)
(:french-fries 275)
(:side-salad 335)
(:hot-wings 355)
(:mozzarella-sticks 420)
(:sampler-plate 580)))
(defun appetizers (limit items)
(let ((res (make-hash-table :test 'equal)))
(labels ((rec (total acc)
(if (= total limit)
(setf (gethash (sort acc #'string<= :key #'symbol-name) res) total)
(loop for (name val) in items for
new-total = (+ total val)
when (>= limit new-total)
do (rec new-total (cons name acc))))))
(rec 0 nil)
(alexandria:hash-table-alist res))))
我认为这应该给我正确的结果。给定一个limit 和一个(<item-name> <price>) 的表
- 从
0和空列表开始。 - 如果总和等于
limit,则对该结果进行排序并存储。 - 对于输入项目表中的每个项目,如果将其添加到已选择项目的价格将小于或等于限制,则重复其成本添加到运行总计,并添加到已选择项目列表。
- 完成后,收集所有记录的结果。
问题是,它返回不正确的输出:
CL-USER> (appetizers 1505 +items+)
(((:HOT-WINGS :HOT-WINGS :HOT-WINGS :MIXED-FRUIT :MIXED-FRUIT :SAMPLER-PLATE)
. 1505)
((:HOT-WINGS :HOT-WINGS :MIXED-FRUIT :SAMPLER-PLATE) . 1505)
((:HOT-WINGS :MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT :SAMPLER-PLATE
:SAMPLER-PLATE :SAMPLER-PLATE :SAMPLER-PLATE)
. 1505)
((:HOT-WINGS :MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT
:SAMPLER-PLATE :SAMPLER-PLATE :SAMPLER-PLATE :SAMPLER-PLATE)
. 1505)
((:MIXED-FRUIT :SAMPLER-PLATE :SAMPLER-PLATE) . 1505)
((:HOT-WINGS :SAMPLER-PLATE :SAMPLER-PLATE :SAMPLER-PLATE) . 1505)
((:HOT-WINGS :HOT-WINGS :HOT-WINGS :SAMPLER-PLATE :SAMPLER-PLATE
:SAMPLER-PLATE)
. 1505)
((:SAMPLER-PLATE :SAMPLER-PLATE) . 1505)
((:HOT-WINGS :HOT-WINGS :MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT
:MIXED-FRUIT :SAMPLER-PLATE :SAMPLER-PLATE :SAMPLER-PLATE)
. 1505)
((:HOT-WINGS :HOT-WINGS :HOT-WINGS :MIXED-FRUIT :MIXED-FRUIT :SAMPLER-PLATE
:SAMPLER-PLATE :SAMPLER-PLATE)
. 1505)
((:MIXED-FRUIT :MIXED-FRUIT :SAMPLER-PLATE :SAMPLER-PLATE :SAMPLER-PLATE)
. 1505))
CL-USER>
它声称它们每个都是1505 的开胃菜,但实际上不是:
CL-USER> (defun cost-of (chosen-items items)
(loop for i in chosen-items
sum (second (assoc i items))))
COST-OF
CL-USER> (loop for (lst . quote-total-endquote)
in (appetizers 1505 +items+)
collect (cost-of lst +items+))
(2075 1505 3320 3535 1375 2095 2805 1160 3525 3235 2170)
CL-USER>
如果我尝试一步一步地打印出来
(defun appetizers (limit items)
(let ((res (make-hash-table :test 'equal)))
(labels ((rec (total acc)
(format t "Recurring with ~s ~s~%" total acc)
(if (= total limit)
(progn
(format t "Done: ~s ~s (~s)~%" total acc (cost-of acc items))
(setf
(gethash (sort acc #'string<= :key #'symbol-name) res)
total))
(loop for (name price) in items
for new-total = (+ total price)
when (>= limit new-total)
do (rec new-total (cons name acc))))))
(rec 0 nil)
(alexandria:hash-table-alist res))))
我得到了一些相当奇怪的结果
CL-USER> (appetizers 1505 +items+)
Recurring with 0 NIL
Recurring with 215 (:MIXED-FRUIT)
Recurring with 430 (:MIXED-FRUIT :MIXED-FRUIT)
Recurring with 645 (:MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT)
Recurring with 860 (:MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT)
Recurring with 1075 (:MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT
:MIXED-FRUIT)
Recurring with 1290 (:MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT
:MIXED-FRUIT :MIXED-FRUIT)
Recurring with 1505 (:MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT
:MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT)
Done: 1505 (:MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT
:MIXED-FRUIT :MIXED-FRUIT :MIXED-FRUIT) (1505)
Recurring with 1350 (:FRENCH-FRIES :MIXED-FRUIT) ;; wrong
Recurring with 1410 (:SIDE-SALAD :MIXED-FRUIT) ;; wrong
Recurring with 1430 (:HOT-WINGS :MIXED-FRUIT) ;; wrong
所有标记为wrong 的行似乎都有一个:mixed-fruit 的价格为1075,实际上是5x:mixed-fruit 的价格。
我已经盯着这个足够长的时间了,我很确定我自己找不到这个错误。我这里哪里出错了?
【问题讨论】:
标签: common-lisp knapsack-problem