haykart
haykart

Reputation: 957

Algorithm for Filling bag maximally (this is not the knapsack 0/1)

I am working on some task which requires from me to solve the following algorithmic problem:


- You Have collection of items (their weights): [w1, w2, ..., wn]
- And You have a bag which weight is: W
- It is Needed to fill the bag maximally (fill as much as possible) with the subset of given items.

So this is not "Knapsack 0/1" problem, as we deal only with weights (we have only one parameter for item). Therefore I assume that it might have a solution (Knapsack is NP-complete) or some kind of algorithm which gives approximately correct result.

Please don't suggest me "greedy algorithms", because I believe that there should be an algorithm which gives better results. I think that it should be an algorithm which uses "dynamic programming".

Thank you in advance :)

Upvotes: 3

Views: 7554

Answers (3)

Khai Vu
Khai Vu

Reputation: 2138

It look like Spoj problem. And my solusion to solve:

#include <bits/stdc++.h>

using namespace std;

int TimTongLonNhatCoGioiHan(int*arr, int songuoichoi, int gioihan){

  int hmm = (int)(songuoichoi*songuoichoi/2);
  int map[hmm];

  int dem = 0, i, j, ox = songuoichoi - 1, oy = 0, result = 0, sum;
  for(i = ox; i > oy; --i){
    for(j = oy; j < ox; ++j){
      map[dem] = arr[i] + arr[j];

      // tinh tong lon nhat cua 3 so
      for(int k = 0; k < songuoichoi; ++k){
        if(k == j || k == i)
          continue;
        sum = map[dem] + arr[k];
        if(sum > result && sum <= gioihan)
          result = sum;
      }
      dem++;
    }
    -- ox;
  }

  return result;
}

int main() {
  int sophantu = 0, songuoichoi = 0, gioihan = 0;
  cin>>sophantu;
  while(sophantu-->0){
    cin>>songuoichoi;
    int i = 0;
    int arrCanNang[songuoichoi];
    for(; i<songuoichoi; ++i){
      cin>>arrCanNang[i];
    }
    cin>>gioihan;

    cout<<TimTongLonNhatCoGioiHan(arrCanNang, songuoichoi, gioihan)<<"\n";
  }
  return 0;
}

For simple, you can create a matrix [w1, w2, ..., wn] x [w1, w2, ..., wn], put sum(Wi, Wj), foreach k and find MAX sum(Wi, Wj) + Wk.

Upvotes: 0

Marco A.
Marco A.

Reputation: 43662

In this particular instance you get maximum benefit by minimizing the free space in the bag and therefore by considering weight as a value. This problem is commonly referred to as subset sum problem and is a particular case of knapsack problems family.

The DP relation looks like the following

enter image description here

where at each step you try to find the maximum value (which does not exceed the bag's capacity) among the previous elements set plus the new element

A C++ implementation of the subset sum problem to answer the question "can I fill the bag entirely given these elements?" and driver follows

bool ssp(const vector<int>& v, const int& N) {

  vector<vector<int>> m( v.size() + 1 /* 1-based */,
                         vector<int>(N + 1 /* 1-based */, 0) );

  // The line above also took care of the initialization for base
  // cases f(i,0) = 0 and f(0,b) = 0

  for (int i = 1; i <= v.size(); ++i) { // For each subset of elements
    for (int b = 1; b <= N; ++b) { // For each subcapacity
      int opt1 = m[i - 1][b];
      int opt2 = -1;
      if (b - v[i - 1] >= 0) { // No caching to keep this readable
        opt2 = m[i - 1][b - v[i - 1]] + v[i - 1];
        if (opt2 > b)
          opt2 = -1; // Not allowed
      }
      m[i][b] = max(opt1, opt2);
    }
  }

  return (m[v.size()][N] == N);
}

int main() {

  const vector<int> v = { 1, 3, 7, 4 };
  const int N = 11;

  cout << "Subset sum problem can be solved with the given input: "
       << boolalpha << ssp(v, N); // true

  return 0;
}

The complexity is O(N⋅I) where I is the number of elements in the starting set. This is a pseudopolynomial complexity.

Source: Knapsack problem

Upvotes: 2

Codor
Codor

Reputation: 17605

The described problem in fact is not the 0-1-Knapsack problem, but a special case thereof, also called the Maximum Subset Sum problem, which is desribed here. It is NP-complete, which means that it is not easier than 0-1-Knapsack complexity-wise.

That being said, it can be solved by any optimization algorithm intended for the 0-1-Knapsack problem by setting the item profits equal to their weights. In total, it can be solved to optimality using the following dynamic programming algorithm; s[i] denotes the size if the i-th item and m is an integer-valued state space where m[i,s] denotes the maximum value attainable by using items from the item rage {0,...i}.

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 s[i] > j then:
            m[i, j] := m[i-1, j]
        else:
            m[i, j] := max(m[i-1, j], m[i-1, j-s[i]] + s[i])

As they are mentioned in the original question, the following greedy algorithm yields a 2-approximation, which is a modification of a similar algorithm for the Knapsack problem.

1. select any subset of the items such that there is no other
   item which can be feasibly chosen
2. select the largest item
3. out of 1. and 2., choose the subset which yields the larger total size

Upvotes: 2

Related Questions