带有两个权重的背包算法

时间:2016-07-03 06:48:38

标签: algorithm time-complexity dynamic-programming knapsack-problem greedy

我有以下问题:

  

解决背包0-1问题(不是小数)假设每一个   对象有权重w1w2(只有两个权重)。容量= W,算法   必须在O(nlogn)上运行。

我试着解决,贪心算法不起作用,动态编程算法是O(n * W)。

任何人都可以给我提示。 谢谢。

2 个答案:

答案 0 :(得分:2)

您可以将元素分为两部分,一部分以w1作为权重,另一部分以w2作为权重。

现在,您可以根据成本对上述两个列表进行排序。

  

A1:按成本按降序排序,权重为w1的元素

     

A2:按成本按降序排序,权重为w2的元素

现在你可以创建数组的前缀和,让我们调用它们P1, P2

示例:

Array : 11, 8, 5, 3, 1

Prefix sum : 11, 19, 24, 27, 28

一旦你有前缀sum,你可以迭代P1数组并尝试包含第i个索引的元素。 一旦我们将元素包含到i,我们就会有W - (w1*i)权重,然后我们可以尝试在P2数组中对此权重进行二分搜索。

伪代码:

A : input array
create A1 : cost of elements having w1 weight
create A2 : cost of elements having w2 weight

sort(A1, descending)
sort(A2, descending)

for(i=0;i <= A1.size();i++){
      P1[i] = P1[i-1] + A1[i];
      P2[i] = P2[i-1] + A2[i];
}
int ans = 0;
for(i=1;i<=A1.size();i++){
      if(i * w1 <= W){
            int wLeft = W - i * w1;
            int ans = binarySearch(wLeft, P2) + p1[i];  
      }
}
ans => contains the answer

//-----------Binary search function
int binarySearch(int weight, P2[]){
      int start = 0, end = P2.size(), ans = 0;
      int mid = (start+end)/2;
      while(start <= end){
            if(mid * w2 <= weight){
                  start = mid + 1;
                  ans = max(ans, p2[mid]);
            }else{
                  end = mid - 1;
            }
      }
return ans
}

整体复杂度为O(n * log n)

正如@j_random_hacker所建议的,我们可以迭代第二个前缀数组,因为我们只能通过添加元素来改进解决方案,它会通过删除二进制搜索来简化代码。

答案 1 :(得分:1)

由于您有两种权重:

首先使用尽可能多的元素w1或者适合W.尽可能多地使用w2。

当你得到这样的背包时,在每次迭代中都会弹出一个w1元素,然后放入尽可能多的w2或者你可以使用的w2。只要背包中有w1元素,就可以这样做。

所有迭代的背包最大重量将是你的,并且算法将在O(n)中运行