0/1背包见证人

时间:2014-10-25 01:39:00

标签: algorithm dynamic-programming knapsack-problem

我写了一个背包类,我用它来解决背包算法。该类工作并使用动态编程算法来解决问题。

我已经在代码中实现了一些优化,以便我使用线性O(W)空间来找到最大值,但是当我尝试找到见证时,我仍然需要O(nW)空间来保持布尔表。

有人能告诉我是否有可能找到背包的见证人,其容量最大且空间较小且复杂度为O(nW),这里W是背包容量。

如果您认为代码中可能会有更多优化,请告诉他们。

class Knapsack{
private:
  vector< int > value, weight, answer, DP;
  vector< bool > isin;
  int capacity;

public:
  Knapsack( vector< int > value, vector< int > weight, int capacity, bool needWitness ){
    this->value = value;
    this->weight = weight;
    this->capacity = capacity;

    this->answer.clear(); this->isin.clear(); this->DP.clear();
    this->DP.resize( capacity + 1, false );

    if ( needWitness ){
      this->isin.resize( value.size() * (capacity + 1), false );
      solveWithWitness();
    }
    else{
      solveWithoutWitness();
    }

  }

  void solveWithoutWitness(){
    for ( int i = 0; i < value.size(); i++ ){
      for ( int w = capacity; w >= weight[i]; w-- ){
        if ( DP[w] < value[i] + DP[w - weight[i]] ){
          DP[w] = value[i] + DP[w - weight[i]];
        }
      }
    }
  }

  void solveWithWitness(){
    for ( int i = 0; i < value.size(); i++ ){
      for ( int w = capacity; w >= weight[i]; w-- ){
        if ( DP[w] < value[i] + DP[w - weight[i]] ){
          DP[w] = value[i] + DP[w - weight[i]];
          isin[ i*capacity + w ] = true;
        }
      }
    }
    int position = value.size()-1;
    int w = capacity;
    while ( position >= 0 ){
      if ( isin[ position*capacity + w ] ){
        answer.push_back( position );
        w -= weight[position];
      }
      position--;
    }
  }


  vector< int > getWitness(){
    return this->answer;
  }

  int solution(){
    return DP[capacity];
  }

};

1 个答案:

答案 0 :(得分:0)

你在整个地方使用O,所以我可以给你一个理论解决方案,它有点复杂和笨拙,仍然可以满足你想要的时间范围:

运行无见证DP,持续n / 2步;它告诉您只使用前n / 2个项目可以到达哪个W权重。现在为剩余的n / 2步骤运行DP,记录从前n / 2项到达每个单元需要多少重量。

如果你以递归方式天真地应用这个过程,你会得到一个时间重复,看起来像T(n,W)&lt; = 2T(n / 2,W)+ O(nW),其解是O(n log(n)W)。这还不够好。

但我们计算出前n / 2项需要多少重量。叫那个w。我们只需要关心DP阵列的第一个w条目。所以前半个递归应该花费T(n / 2,w)时间,后半个递归应该花费T(n / 2,Ww)时间,并且到达那里所需的工作需要O(nW)时间。 / p>

形式T(n,W)的重现的解决方案&lt; = max(0 <= w <= W)T(n / 2,w)+ T(n / 2,Ww)+ O(nW)实际上是O(nW)。您可以通过想象一个最初为零的n×W矩形来直观地看到这一点。具有n'项和权重W'的递归背包调用在一些n'-by-W'子矩形中为每个条目添加1。然后第一级递归增加总共nW,第二级nW / 2,第三级nW / 4,依此类推,给你几何系列。