有界0-1多背包的任何伪多项式算法?

时间:2013-04-14 13:41:00

标签: algorithm optimization constraint-programming knapsack-problem

假设有n个项目,例如i 1 ,i 2 ,.... i n ,每个项目都有一个已知有界权重w 1 ,w 2 ,... w n 。还有一套m背包,例如k 1 ,k 2 和k m 。背包是同质的,它们都具有相同的容量W.功能F可以确定每个背包的得分。 F的输入是每个背包中的项目。所以,

Score of each knapsack i = F(Items in knapsack i)

现在我想以背包方式将一些物品放在背包中:

  1. 背包中物品的重量不超过其容量W.
  2. 所有背包的得分总和最大
  3. 是否存在针对此问题的多项式时间解决方案?

    注意:问题是0-1,即每个项目都可以选择。所有问题参数都是有界的。

    编辑1:是否有可能将此问题减少到装箱包装,然后认为这是一个NP难问题?

    编辑2 在此问题中,每个项目都有三个属性,例如属性a i ,b i 和c i 。 F函数是一个线性函数,它获取其中项目的属性并生成输出。

    编辑3: this paper似乎为多背包问题提出了一个精确的解决方案。可以用在我的情况下吗?

1 个答案:

答案 0 :(得分:1)

这个怎么样?

鉴于Haskell中针对0-1背包问题的标准动态解决方案,找到了here

inv = [("map",9,150), ("compass",13,35), ("water",153,200), ("sandwich",50,160),
       ("glucose",15,60), ("tin",68,45), ("banana",27,60), ("apple",39,40),
       ("cheese",23,30), ("beer",52,10), ("cream",11,70), ("camera",32,30),
       ("tshirt",24,15), ("trousers",48,10), ("umbrella",73,40), 
       ("trousers",42,70), ("overclothes",43,75), ("notecase",22,80),
       ("sunglasses",7,20), ("towel",18,12), ("socks",4,50), ("book",30,10)]

knapsack = foldr addItem (repeat (0,[])) where
    addItem (name,w,v) list = left ++ zipWith max right newlist where
        newlist = map (\(val, names)->(val + v, name:names)) list
        (left,right) = splitAt w list

main = print $ (knapsack inv) !! 400

我们添加了填充机制,将库存排列顺序放入下一个有空间的背包中,

stuff (name,w,v) left (v2,[]) = (v2,left)
stuff (name,w,v) left (v2,(cap, lst):xs) =
  if w <= cap 
     then (v + v2, left ++ [(cap - w, (name,w,v):lst)] ++ xs) 
     else stuff (name,w,v) (left ++ [(cap,lst)]) (v2,xs)

并将其替换为映射函数。把它们放在一起:

inv = [("map",9,150), ("compass",13,35), ("water",153,200), ("sandwich",50,160),
       ("glucose",15,60), ("tin",68,45), ("banana",27,60), ("apple",39,40),
       ("cheese",23,30), ("beer",52,10), ("cream",11,70), ("camera",32,30),
       ("tshirt",24,15), ("trousers",48,10), ("umbrella",73,40), 
       ("trousers",42,70), ("overclothes",43,75), ("notecase",22,80),
       ("sunglasses",7,20), ("towel",18,12), ("socks",4,50), ("book",30,10)]

capacity = 200::Int
numKnapsacks = 3

stuff (name,w,v) left (v2,[]) = (v2,left)
stuff (name,w,v) left (v2,(cap, lst):xs) =
  if w <= cap 
     then (v + v2, left ++ [(cap - w, (name,w,v):lst)] ++ xs) 
     else stuff (name,w,v) (left ++ [(cap,lst)]) (v2,xs)

knapsack = foldr addItem (repeat (0, replicate numKnapsacks (capacity,[]))) 
  where addItem (name,w,v) list = left ++ zipWith max right newlist 
          where newlist = map (stuff (name,w,v) []) list
                (left,right) = splitAt w list

main = print $ (knapsack inv) !! 600


OUTPUT(每个背包的剩余重量容量和内容后面的总值):

*Main> main
(1062,[(1,[("map",9,150),("tshirt",24,15),("trousers",42,70),
           ("overclothes",43,75),("notecase",22,80),("sunglasses",7,20),
           ("towel",18,12),("socks",4,50),("book",30,10)]),
       (0,[("compass",13,35),("cheese",23,30),("cream",11,70),
           ("camera",32,30),("trousers",48,10),("umbrella",73,40)]),
       (1,[("sandwich",50,160),("glucose",15,60),("tin",68,45),("banana",27,60),
           ("apple",39,40)])])