【问题标题】:Knapsack solution with Backtraking in c++C ++中带有回溯的背包解决方案
【发布时间】:2014-06-17 03:00:06
【问题描述】:

我在尝试使用回溯解决背包问题时遇到了麻烦。

例如,对于以下值,背包函数将返回 14 作为解,但正确的结果应该是 7。

int n = 3, weights[] = {2, 3, 1}, values[] = {6, 15, 7};

int solution = 0, max = 2;


void Knapsack (int i, int max, int value, int *solution)
{
  int k;

  for (k = i; k < n; k++) {
    if (weights[k] <= max) {
      Knapsack (k, max - weights[k], value + values[k], solution);

      if (value+ values[k] > *solution) 
         *solution= value + values[k];
    }
  }
}

这里有什么问题?

【问题讨论】:

  • 您是否尝试过使用真正最小的问题(即较小的values[])并单步执行代码,直到您发现它出错,然后思考为什么?或者,将一些 std::cout &lt;&lt; ... 行放入循环中?

标签: c++ backtracking knapsack-problem


【解决方案1】:
#include<iostream>
#include<vector>

using namespace std;

int weights[] = {2, 3, 1}, values[] = {6, 15, 7};

int solution = 0, n = 3;

std::vector<int> vsol;
std::vector<int> temp;

bool issol;


void Knapsack (int i, int max, int value)
{
  for (int k = i; k < n; k++) {
    if ( max > 0)
    {
        if (weights[k] <= max)
        {
          temp.push_back(k);
          if (value+ values[k] >= solution)
          {
            solution = value + values[k];
            issol = true;
          }
        }
        if ( (k+1) < n)
        {
          Knapsack (k+1, max - weights[k], value + values[k]);
        }
        else
        {
          if (issol == true)
          {
            if (! vsol.empty()) vsol.clear();
            std::move(temp.begin(), temp.end(), std::back_inserter(vsol));
            temp.clear();
            issol = false;
          } else temp.clear();
          return;
        }
    }
    else
    {
        if (issol == true)
        {
            if (! vsol.empty()) vsol.clear();
            std::move(temp.begin(), temp.end(), std::back_inserter(vsol));
            temp.clear();
            issol = false;
        } else temp.clear();
        return;
    }
  }
}

int main()
{
    Knapsack(0, 2, 0);
    cout << "solution: " << solution << endl;
    for(vector<int>::iterator it = vsol.begin(); it != vsol.end(); it++)
        cout << *it << " ";
    return 0;
}

再次调用背包函数时,需要将 k 加 1 以将索引向前移动。

添加了打印解决方案索引位置的代码。如果存在多个解决方案(即相同的总数),将仅打印最后一个解决方案的位置。

【讨论】:

  • 在这种情况下保存解决方案的元素是否容易?
  • 当然可以,您可以使用容器(数组或其他任何东西,最好是 STL 容器)来存储权重数组的索引位置(以及相应的值)
  • 在递归调用之前这样做的正确位置?
  • 如果不需要递归,那么我建议把背包改成循环组合,这样可以更容易识别最终结果的索引位置。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多