这类似于背包还是改变算法?

时间:2014-10-11 17:39:33

标签: java algorithm knapsack-problem

  

这个问题涉及尝试适合的项目   不同的重量放入一个袋子,使袋子最终用一个   指定总重量或最接近指定总重量。

示例1: - 袋子最大可承重240公斤

项目1-60kg,项目2-30kg,项目3-55kg,项目4-60kg,项目5-80kg,项目6-40kg,项目7-7kg,

此处所选项目应为Item1,Item4,Item5和Item6(60 + 60 + 80 + 40 = 240 kg)

示例2: - 袋子最大可承重180公斤

Item1-60kg,Item2-30kg,Item3-55kg,Item4-30kg,Item5-70kg,Item6-48kg

此处所选项目应为Item1,Item4,Item5和Item6(60 + 70 + 48 = 178 kg)

最接近180 kg

这是我的模板方法

public List getSelectedItems(List<Presentation> inputList, int knapsackCapacity){
List selectItems;

// optimized algorith  which returns selectItems and inputList containing  the 
//left out items i.e which are not selected;

return selectItems;
}

网上有些人称之为Knapsack problem最简单的形式,因为它没有与之相关的任何利益/利润,有些人称之为Change-making problem

无论它属于什么类别,我都无法获得此算法,因此无法使Java程序脱颖而出。这里有什么帮助吗?

3 个答案:

答案 0 :(得分:3)

使用动态编程可以在伪多项式时间(O(nW))中最佳地解决此问题。你需要做的就是修改一下Knapsack 0/1的解决方案:

if w[i] > W
    m[i,W] = m[i-1,W]
else if W - m[i-1, W] < W - m[i-1, W - w[i]] + w[i]
    m[i,W] = m[i-1,W]
else
    m[i-1, W - w[i]] + w[i]

W是权重限制,w是元素权重数组。不同之处在于您必须最小化W与结果之间的差异,而不是最大化值的总和。

以下是具有所需修改的wikipedia解决方案:

// Input:
// Weights (stored in array w)
// Number of distinct items (n)
// Knapsack capacity (W)
for j from 0 to W do
  m[0, j] := 0  // Initialize to 0
end for 
for i from 1 to n do    // for every element in the array
  for j from 0 to W do  // for every possible weight
    if w[i] > j then    // if the element's weight is higher than the max
      m[i, j] := m[i-1, j]  // use the solution that excludes the element
    // else if the diff between the solution that excludes the element and max weight
    // is smaller than the one that uses it, use the former.
    else if (j - m[i-1, j]) < (j - m[i-1, j - w[i]] + w[i])
      m[i, j] := m[i-1, j]
    // else use the element's weight in the solution
    else
      m[i, j] := m[i-1, j - w[i]] + w[i]
    end if

2D数组m是记忆表,在算法结束时,m[k, p]为从0到k的元素保留了最佳权重p的最佳解决方案}。

编辑:我在C++中实现并测试了它,它应该很容易移植到Java:

template<typename T>
long Weight(const T& w, int size, const int W)
{
    vector<vector<int>> m(size+1, vector<int>(W+1, 0));

    for(int i = 1; i <= size; ++i)
    {
        for(int j = 0; j <= W; ++j)
        {
            if(w[i-1] > j)
            {
                m[i][j] = m[i-1][j];
            }
            else if((j - m[i-1][j]) < (j - (m[i-1][j - w[i-1]] + w[i-1])))
            {
                m[i][j] = m[i-1][j];
            }
            else
            {
                m[i][j] = m[i-1][j - w[i-1]] + w[i-1];
            }
        }
    }

    return m[size][W];
}

答案 1 :(得分:0)

我喜欢这个问题所以只想分享我的方法

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class Test {

  public static void main(String[] args) {


    List<Presentation> l = new ArrayList<Presentation>();
    Presentation p1=new Presentation("one",20);
    Presentation p2=new Presentation("two",20);
    Presentation p3=new Presentation("three",20);
    Presentation p4=new Presentation("four",20);
    Presentation p5=new Presentation("five",20);
    Presentation p6=new Presentation("six",20);
    Presentation p7=new Presentation("seven",20);
    Presentation p8=new Presentation("eight",20);
    Presentation p9=new Presentation("nine",20); 
    Presentation p10=new Presentation("ten",90);
    Presentation p11=new Presentation("eleven",90);
    l.add(p1);
    l.add(p2);
    l.add(p3);
    l.add(p4);
    l.add(p5);
    l.add(p6);
    l.add(p6);
    l.add(p7);
    l.add(p8);
    l.add(p9);
    l.add(p10);
    l.add(p11);
    System.out.println(getSelectedItems(l,200));
  }

  private static List<String>  getSelectedItems(List<Presentation> l, int knapsackCapacity) {
    int sum=0;
    int temp=0;
    PresentationCompare compare=new PresentationCompare();
    List<String> s=new ArrayList<String>();
    while(sum!=knapsackCapacity && sum<knapsackCapacity && l.size()!=0){
      Presentation maxObj=Collections.max(l,compare);
      temp+=maxObj.getWeight();
      if(temp<=knapsackCapacity){
        sum=temp;
        s.add(maxObj.getName());
        l.remove(l.indexOf(maxObj));
      }else{
        l.remove(l.indexOf(maxObj));
        temp=sum;
      }
    }
    return s;
  }



}

import java.util.Comparator;


public class PresentationCompare implements Comparator<Presentation> {

  public int compare(Presentation o1, Presentation o2) {
    return o1.weight-o2.weight;
  }

}

答案 2 :(得分:0)

我同意不真实的分析。但是这可以通过背包解决方案的任何修改来解决这个问题。只需考虑与权重相同的权重值。然后我们不必修改背包程序。这是示例

import java.util.ArrayList;
import java.util.List;
public class Knapsack {

    public static void main(String[] args) {

        int[] weight = {60, 30, 55, 60, 80, 40, 7};
        int[] value = {60, 30, 55, 60, 80, 40, 7};
        int targetSum = 31;

        knapsack(weight, value, targetSum);

    }

    public static void knapsack(int[] weight, int[] value, int targetSum) {

        int[][] weightValMatrix = new int[weight.length + 1][targetSum + 1];

        for (int i = 0; i < weight.length; i++) {
            for (int k = 0; k < targetSum + 1; k++) {
                weightValMatrix[i][k] = 0;
            }

        }

        for (int i = 1; i < weight.length + 1; i++) {
            for (int k = 1; k < targetSum + 1; k++) {
                if (k < weight[i - 1]) {
                    weightValMatrix[i][k] = weightValMatrix[i - 1][k];
                } else {
                    int valueInclusiveCurrentWeight = value[i - 1];
                    if ((k - weight[i - 1]) > 0) {
                        valueInclusiveCurrentWeight = valueInclusiveCurrentWeight
                                + weightValMatrix[i - 1][k - weight[i - 1]];
                    }

                    int valueExcludingCurrentWeight = weightValMatrix[i - 1][k];
                    weightValMatrix[i][k] = valueInclusiveCurrentWeight >= valueExcludingCurrentWeight ? valueInclusiveCurrentWeight
                            : valueExcludingCurrentWeight;

                }

            }



        }



        for (int i = 1; i < weight.length + 1; i++) {

            for (int k = 1; k < targetSum + 1; k++) {

                System.out.print(weightValMatrix[i][k]);

                if(k == targetSum){
                    System.out.println("");
                }
            }
        }


        System.out.println("final value is " + weightValMatrix[weight.length][targetSum]);

        List<Integer> finallySelectedWeightIndex = new ArrayList<Integer>();

        findActualWeightIndex(weightValMatrix, weight.length, targetSum, finallySelectedWeightIndex, weight);

        for(int index:finallySelectedWeightIndex){
            System.out.println("weight is " + weight[index-1] + " value is "+ value[index-1]);
        }


    }


    public static void findActualWeightIndex(int[][] weightValMatrix, int row, int column, 
            List<Integer> finallySelectedWeightIndex, int[] weight) {

        if(row==0 || column==0){
            return;
        }

        if(weightValMatrix[row][column]==weightValMatrix[row-1][column]){
            findActualWeightIndex(weightValMatrix, row-1, column, finallySelectedWeightIndex, weight);
        }else{
            finallySelectedWeightIndex.add(row);
            findActualWeightIndex(weightValMatrix, row-1, column - weight[row-1] , finallySelectedWeightIndex, weight);
        }
    }

}