【问题标题】:Knapsack with selection from distinct groups从不同组中选择的背包
【发布时间】:2015-04-19 12:03:37
【问题描述】:

我有一个关于背包问题的变体,我正在努力寻找一个有效的解决方案。

假设您有多个项目组。每个组可以有任意数量的项目,每个项目都有一个值和权重。问题是要找到具有最大总价值、重量

也就是说,假设您有数百种物品可供挑选,但您必须带一份三明治、一份饮料、一份小吃、一个手电筒等。不仅是您不能从任何组中挑选超过一件,而是如果有 g 个组,你必须在一天结束时得到正好 g 个项目。

看起来这应该比基本问题更快,因为很多组合都是无效的,但我正在努力寻找解决方案。

【问题讨论】:

  • 您的问题似乎有缺陷。如果准确选择g物品的要求和重量限制冲突怎么办?
  • 一个简单(但“组”数量呈指数增长)的解决方案是为每个组添加布尔维度,以指示是否从该集合中选择了一个项目。
  • @Lingxi - 好点。假设我们知道(因为我们可以很容易地提前确认)至少存在一种解决方案。
  • @amit - 所以只是跳过已经使用的组中的项目?这样会不会冒着创建次优答案和创建不是每个组都代表的答案的风险?

标签: algorithm knapsack-problem


【解决方案1】:

C++ 中的示例代码。该函数返回最大可实现值,如果不存在可行解决方案,则返回 -1。它在O(n * max_weight) 中运行,其中n 是计数所有组的项目总数,max_weight 是重量限制。复杂性与解决原始背包问题的经典算法相同。该代码实现了 Evgeny Kluev 答案中的算法。

int CalcMaxValue(const std::vector<std::vector<int>>& weight,
                 const std::vector<std::vector<int>>& value,
                 int max_weight) {
    std::vector<int> last(max_weight + 1, -1);
    if (weight.empty()) return 0;
    for (int i = 0; i < weight[0].size(); ++i) {
        if (weight[0][i] > max_weight) continue;
        last[weight[0][i]] = std::max(last[weight[0][i]], value[0][i]);
    }
    std::vector<int> current(max_weight + 1);
    for (int i = 1; i < weight.size(); ++i) {
        std::fill(current.begin(), current.end(), -1);
        for (int j = 0; j < weight[i].size(); ++j) {
            for (int k = weight[i][j]; k <= max_weight; ++k) {
                if (last[k - weight[i][j]] < 0) continue;
                current[k] = std::max(current[k], last[k - weight[i][j]] + value[i][j]);
            }
        }
        std::swap(current, last);
    }    
    return *std::max_element(last.begin(), last.end());
}

【讨论】:

  • 感谢您的示例。关于如何改变它以返回多个最佳解决方案的任何想法?
【解决方案2】:

对于整数权重且限制不太大,您可以应用通常的动态规划方法(稍作修改)。

使用一对将每个可能的权重映射到值的数组。这些数组之一 (A) 保存已处理的那些组的结果。其他数组 (B) 用于接收来自第一个数组和当前正在处理的组的项目的值的总和。从一组到另一组时,交换这些数组并清除数组B。最后(像往常一样)你必须从数组B 中获取最大值。

渐近复杂度与通常的动态规划算法相同。但是您认为should be faster to do than the basic problem 的结论有些正确,因为您可以彼此独立地处理同一组中的每个元素,因此对通常算法的这种修改具有更好的可并行性。

【讨论】:

  • 我不确定我是否理解。使用典型的方法,其中 m[i,w] 是通过使用前 i 项的权重小于 w 的最大可实现值...是建议的 A[n,w] m[i,w] 的最大值所有我都在第 n 组?还是 A 仍然包含所有单独的结果?
  • 我建议将 m[i,j] 的含义更改为以下内容:通过使用前 i (不是项目),权重小于 j 的最大可实现值。然后 m 的奇数行存储在数组 A 中,偶数行 - 在 B 中,因为仅存储最后 2 行就足够了(尽管如果您需要简单的方法来获取解决方案中使用的所有项目,最好保留整个矩阵)。我假设按组对项目进行排序,然后使用组中的所有项目生成下一行。
  • 谢谢,Evgeny 和@Lingxi,但是这不会导致无法包含来自一个或多个组的项目吗?这是否可以通过找到所有“未来”组所需的最小权重并调整 max_weight 以在每次迭代中考虑到这一点来解决?这样做不会带来次优解决方案的风险吗?
  • @DovRosenberg 该算法从每个组中只选择一个项目。如果不存在可行的解决方案,则返回 -1
  • @DovRosenberg:很难说没有看到实际的算法,但最有可能通过调整 max_weight 来解决这个问题的尝试会给出次优的解决方案。
猜你喜欢
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-21
相关资源
最近更新 更多