我写了一个背包类,我用它来解决背包算法。该类工作并使用动态编程算法来解决问题。
我已经在代码中实现了一些优化,以便我使用线性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];
}
};
答案 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,依此类推,给你几何系列。