Variant of Knapsack

2019-08-13 11:17发布

问题:

I'm working on a program to solve a variant of the 0/1 Knapsack problem.

The original problem is described here: https://en.wikipedia.org/wiki/Knapsack_problem. In case the link goes missing in the future, I will give you a summary of the 0/1 Knapsack problem (if you are familiar with it, jump this paragraph): Let's say we have n items, each with weight wi and value vi. We want to put items in a bag, that supports a maximum weight W, so that the total value inside the bag is the maximum possible without overweighting the bag. Items cannot have multiple instances (i.e., we only have one of each). The objective of the problem is to maximize SUM(vi.xi) so that SUM(wi.xi) <= W and xi = 0, 1 (xi represents the state of an item being or not in the bag).

For my case, there are small differences in both conditions and objective:

  • The weight of all items is 1, wi = 1, i = 1...n

  • I always want to put exactly half the items in the bag. So, the maximum weight capacity of the bag is half (rounded up) of the number of items.W = ceil[n/2] or W = floor[(n+1)/2].

  • Also, the weight inside the bag must be equal to its maximum capacity SUM(wi.xi) = W

Finally, instead of maximizing the value of the items inside the bag, the objective is that the value of the items inside is as close as possible to the value of the items outside. Hence, my objective is to minimize |SUM(vi.-xi) - SUM[vi(1-xi)]|, which simplifies into something like minimize |SUM[vi(2xi - 1)]|.

Now, there is a pseudo-code for the original 0/1 Knapsack problem in the Wikipedia page above (you can find it on the bottom of this text), but I am having trouble adapting it to my scenario. Can someone help? (I am not asking for code, just for an idea, so language is irrelevant)

Thanks!


Wikipedia's pseudo-code for 0/1 Knapsack problem:

Assume w1, w2, ..., wn, W are strictly positive integers. Define m[i,w] to be the maximum value that can be attained with weight less than or equal to w using items up to i (first i items).

We can define m[i,w] recursively as follows:

  • m[0, w]=0
  • m[i, w] = m[i-1, w] if wi > w (the new item is more than the current weight limit)
  • m[i, w]= max(m[i-1, w], m[i-1, w-wi] + vi) if wi <= w.

The solution can then be found by calculating m[n,W].

// Input:
// Values (stored in array v)
// Weights (stored in array w)
// Number of distinct items (n)
// Knapsack capacity (W)

for j from 0 to W do:
    m[0, j] := 0

for i from 1 to n do:
    for j from 0 to W do:
        if w[i-1] <= j then:
            m[i, j] := max(m[i-1, j], m[i-1, j-w[i-1]] + v[i-1])
        else:
            m[i, j] := m[i-1, j]

回答1:

Thanks to @harold, it seems like this problem is not a Knapsack problem, but a Partition problem. Part of the pseudo-code I was seeking is in the corresponding Wikipedia page: https://en.wikipedia.org/wiki/Partition_problem

EDIT: well, actually, Partition problem algorithms tell you whether a Set of items can be partitioned in 2 sets of equal value or not. Suppose it can't, you have approximation algorithms, which say whether you can have the set partiotioned in 2 sets with the difference their values being lower than d. BUT, they don't tell you the resulting sub-sets, and that's what I was seeking.

I ended up finding a question here asking for that (here: Balanced partition), with a code example which I have tested and works fine.