我对背包问题有一些变化,我正在努力寻找有效的解决方案。
假设您有多组商品。每个组可以有任意数量的项目,每个项目都有一个值和重量。问题是找到具有最大总值,重量<的物品组。一些限制,(棘手的部分)只包括每个组中的一个项目是有效的。
也就是说,想象一下你有数百种可供挑选的物品,但你必须吃一个三明治,一个饮料,一个小吃,一个手电筒等。不仅仅是你不能从任何一组中拿走多个,但是如果有g个小组,你必须在一天结束时最后得到总数为g的项目。
看起来这应该比基本问题更快,因为很多组合都是无效的,但我很难找到解决方案。
答案 0 :(得分:2)
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());
}
答案 1 :(得分:1)
对于整数权重而不是太大的限制,您可以应用通常的动态编程方法(略微修改)。
使用一对数组将每个可能的权重映射到值。其中一个数组(A
)保存已处理的组的结果。其他数组(B
)用于接收来自第一个数组和当前正在处理的组的项的值之和。当从一个组到另一个组时,交换这些数组并清除数组B
。最后(像往常一样)你必须得到数组B
中的最大值。
渐近复杂度与通常的动态编程算法相同。但是您的结论是should be faster to do than the basic problem
有点真实,因为您可以相互独立地处理同一组的每个元素,因此通常算法的这种修改可以更好地并行化。