结合两个载体(用几个罐子的内容填充容器)

时间:2014-10-18 13:15:20

标签: clojure

我有两个载体

(def container [{:no 1 :volume 10} {:no 2 :volume 20}])
(def cans [{:no 1 :volume 2} {:no 2 :volume 8} {:no 1 :volume 5} {:no 2 :volume 8}])

我想用罐子装满容器,以便返回这样的东西:

[{:no 1 :volume 10
  :cans [{:no 1 :volume 2} {:no 2 :volume 8}]}
 {:no 2 :volume 20
  :cans [{:no 1 :volume 5} {:no 2 :volume 8}]}]

从而跟踪哪个容器可以进入哪个容器。我开始使用reduce,但是如果不使用变异商店来保存剩余的罐头,就无法理解如何做到这一点。有什么想法吗?

更新

通过填充,我的意思是在第一个容器中装入尽可能多的罐子,直到它装满或接近(罐子的体积总和不超过容器的体积),然后开始填充第二个容器,直到它为止完全或接近,等等。

1 个答案:

答案 0 :(得分:0)

我们不需要为剩余的罐子使用变异商店,因为reduce将序列作为参数,并减少累积函数,在序列的每个元素上调用它。

在下文中,我将容器分成填充/未填充,并将每个罐插入容器中,它将是最紧密的(这有助于优化包装)。

user> (def container [{:no 1 :volume 10} {:no 2 :volume 20}])
#'user/container
user> (def cans [{:no 1 :volume 2} {:no 2 :volume 8} {:no 1 :volume 5} {:no 2 :volume 8}])
#'user/cans
user> 
(def containerized
  (let [containers (map #(assoc % :capacity (:volume %) :cans []) container)
        insert (fn [container can]
                 (-> container
                     (update-in [:capacity] - (:volume can))
                     (update-in [:cans] conj can)))
        accumulator (fn [[filled filling] can]
                      (let [[non-fits [picked & unpicked]]
                            (split-with #(< (:capacity %)
                                            (:volume can))
                                        (sort-by :capacity filling))
                           picked (insert picked can)
                           still-filling (concat non-fits unpicked)]
                        (if (<= (:capacity picked) 0)
                          [(conj filled picked) still-filling]
                          [filled (conj still-filling picked)])))
        filled (reduce accumulator
                       [[] containers]
                       cans)]
    (map #(dissoc % :capacity) (apply concat filled))))

#'user/containerized
user> (clojure.pprint/pprint containerized)
({:cans [{:volume 2, :no 1} {:volume 8, :no 2}], :volume 10, :no 1}
 {:cans [{:volume 5, :no 1} {:volume 8, :no 2}], :volume 20, :no 2})
nil