如何递归地解决'经典'背包算法?

时间:2011-10-15 00:01:28

标签: java algorithm knapsack-problem

这是我的任务

  

背包问题是计算机科学的经典之作。最简单的   形式它涉及尝试将不同重量的物品装入一个   背包,以便背包以指定的总重量结束。   您不需要适合所有项目。例如,假设你想要   你的背包重量只有20磅,你有五件物品,   重量为11,8,7,6和5磅。对于少量商品,   人类通过检查很好地解决了这个问题。那么你   可能只能弄清楚只有8,7和5项的组合   最多可增加20个。

我真的不知道从哪里开始编写这个算法。应用于阶乘和三角数时,我理解递归。但是我现在迷路了。

9 个答案:

答案 0 :(得分:19)

你尝试了什么?

这个想法,考虑到你说的问题(指明我们必须使用递归)很简单:对于你可以采取的每个项目,看看是否更好地接受它。所以只有两条可能的路径:

  1. 你拿走了这个项目
  2. 你不接受
  3. 当你拿走物品时,你将它从列表中删除,然后根据物品的重量减少容量。

    如果您不接受该项目,则从列表中删除,但不会减少容量。

    有时打印递归调用可能会有所帮助。在这种情况下,它可能如下所示:

    Calling 11 8 7 6 5  with cap: 20
     +Calling 8 7 6 5  with cap: 20
     |  Calling 7 6 5  with cap: 20
     |    Calling 6 5  with cap: 20
     |      Calling 5  with cap: 20
     |      Result: 5
     |      Calling 5  with cap: 14
     |      Result: 5
     |    Result: 11
     |    Calling 6 5  with cap: 13
     |      Calling 5  with cap: 13
     |      Result: 5
     |      Calling 5  with cap: 7
     |      Result: 5
     |    Result: 11
     |  Result: 18
     |  Calling 7 6 5  with cap: 12
     |    Calling 6 5  with cap: 12
     |      Calling 5  with cap: 12
     |      Result: 5
     |      Calling 5  with cap: 6
     |      Result: 5
     |    Result: 11
     |    Calling 6 5  with cap: 5
     |      Calling 5  with cap: 5
     |      Result: 5
     |    Result: 5
     |  Result: 12
     +Result: 20
      Calling 8 7 6 5  with cap: 9
        Calling 7 6 5  with cap: 9
          Calling 6 5  with cap: 9
            Calling 5  with cap: 9
            Result: 5
            Calling 5  with cap: 3
            Result: 0
          Result: 6
          Calling 6 5  with cap: 2
            Calling 5  with cap: 2
            Result: 0
          Result: 0
        Result: 7
        Calling 7 6 5  with cap: 1
          Calling 6 5  with cap: 1
            Calling 5  with cap: 1
            Result: 0
          Result: 0
        Result: 0
      Result: 8
    Result: 20
    

    我故意表示调用[8 7 6 5],容量为20,结果为20(8 + 7 + 5)。

    请注意,[8 7 6 5]被调用两次:一次容量为20(因为我们没有服用11次),一次容量为9次(因为确实服用了11次)。

    解决方案的路径:

    11未参加,呼叫[8 7 6 5],容量为20

    8,调用[7 6 5],容量为12(20 - 8)

    7,调用[6 5],容量为5(12 - 7)

    6未采用,调用[5]容量为5

    5,我们零。

    Java中的实际方法可以适用于非常少的代码行。

    由于这显然是家庭作业,我只会用骨架帮助你:

    private int ukp( final int[] ar, final int cap ) {
        if ( ar.length == 1 ) {
            return ar[0] <= cap ? ar[0] : 0;
        } else {
            final int[] nar = new int[ar.length-1];
            System.arraycopy(ar, 1, nar, 0, nar.length);
            fint int item = ar[0];
            if ( item < cap ) {
                final int left = ...  // fill me: we're not taking the item
                final int took = ...  // fill me: we're taking the item
                return Math.max(took,left);
            } else {
                return ... // fill me: we're not taking the item
            }
        }
    }
    

    我确实将数组复制到一个新的数组,效率较低(但无论如何,如果你寻求性能,递归不是去这里的方式),而是更“有效”。

答案 1 :(得分:12)

我必须为我的作业做这个,所以我测试了所有上面的代码(除了Python之外),但它们都不适用于每个角落的情况。

这是我的代码,它适用于每个角落的情况。

static int[] values = new int[] {894, 260, 392, 281, 27};
static int[] weights = new int[] {8, 6, 4, 0, 21};
static int W = 30;

private static int knapsack(int i, int W) {
    if (i < 0) {
        return 0;
    }
    if (weights[i] > W) {
        return knapsack(i-1, W);
    } else {
        return Math.max(knapsack(i-1, W), knapsack(i-1, W - weights[i]) + values[i]);
    }
}

public static void main(String[] args) {
System.out.println(knapsack(values.length - 1, W));}

它没有优化,递归会杀了你,但你可以用简单的memoization来解决这个问题。为什么我的代码简短,正确且易于理解?我刚刚查看了0-1背包问题http://en.wikipedia.org/wiki/Knapsack_problem#Dynamic_programming

的数学定义

答案 2 :(得分:8)

问题基本上是经典背包问题的修改版本,为了简单起见(没有值/好处对应权重)(对于实际:http://en.wikipedia.org/wiki/Knapsack_problem0/1 Knapsack - A few clarification on Wiki's pseudocode,{ {3}},How to understand the knapsack problem is NP-complete?Why is the knapsack problem pseudo-polynomial?)。

以下是在c#中解决此问题的五个版本:

版本1 :使用动态编程(制表 - 通过急切地找到所有求和问题的解决方案到达最终版本) - O(n * W)

版本2 :使用DP但是记忆版本(懒惰 - 只需找到所需的解决方案)

版本3 使用递归来演示重叠的子问题和最佳子结构

版本4 递归(暴力) - 基本上接受的答案

第5版使用#4堆栈(演示删除尾递归)

版本1 :使用动态编程(制表 - 通过急切地找到所有求和问题的解决方案到达最终版本) - O(n * W)

public bool KnapsackSimplified_DP_Tabulated_Eager(int[] weights, int W)
        {
            this.Validate(weights, W);
            bool[][] DP_Memoization_Cache = new bool[weights.Length + 1][];
            for (int i = 0; i <= weights.Length; i++)
            {
                DP_Memoization_Cache[i] = new bool[W + 1];
            }
            for (int i = 1; i <= weights.Length; i++)
            {
                for (int w = 0; w <= W; w++)
                {
                    /// f(i, w) determines if weight 'w' can be accumulated using given 'i' number of weights
                    /// f(i, w) = False if i <= 0
                    ///           OR True if weights[i-1] == w
                    ///           OR f(i-1, w) if weights[i-1] > w
                    ///           OR f(i-1, w) || f(i-1, w-weights[i-1])
                    if(weights[i-1] == w)
                    {
                        DP_Memoization_Cache[i][w] = true;
                    }
                    else
                    {
                        DP_Memoization_Cache[i][w] = DP_Memoization_Cache[i - 1][w];
                        if(!DP_Memoization_Cache[i][w])
                        {
                            if (w > weights[i - 1])
                            {
                                DP_Memoization_Cache[i][w] = DP_Memoization_Cache[i - 1][w - weights[i - 1]];
                            }
                        }
                    }
                }
            }
            return DP_Memoization_Cache[weights.Length][W];
        }

版本2 :使用DP但记忆版本(懒惰 - 只需找到所需的解决方案)

/// <summary>
        /// f(i, w) determines if weight 'w' can be accumulated using given 'i' number of weights
        /// f(i, w) = False if i < 0
        ///           OR True if weights[i] == w
        ///           OR f(i-1, w) if weights[i] > w
        ///           OR f(i-1, w) || f(i-1, w-weights[i])
        /// </summary>
        /// <param name="rowIndexOfCache">
        /// Note, its index of row in the cache
        /// index of given weifhts is indexOfCahce -1 (as it starts from 0)
        /// </param>
        bool KnapsackSimplified_DP_Memoization_Lazy(int[] weights, int w, int i_rowIndexOfCache, bool?[][] DP_Memoization_Cache)
        {
            if(i_rowIndexOfCache < 0)
            {
                return false;
            }
            if(DP_Memoization_Cache[i_rowIndexOfCache][w].HasValue)
            {
                return DP_Memoization_Cache[i_rowIndexOfCache][w].Value;
            }
            int i_weights_index = i_rowIndexOfCache - 1;
            if (weights[i_weights_index] == w)
            {
                //we can just use current weight, so no need to call other recursive methods
                //just return true
                DP_Memoization_Cache[i_rowIndexOfCache][w] = true;
                return true;
            }
            //see if W, can be achieved without using weights[i]
            bool flag = this.KnapsackSimplified_OverlappedSubPromblems_OptimalSubstructure(weights,
                w, i_rowIndexOfCache - 1);
            DP_Memoization_Cache[i_rowIndexOfCache][w] = flag;
            if (flag)
            {
                return true;
            }
            if (w > weights[i_weights_index])
            {
                //see if W-weight[i] can be achieved with rest of the weights
                flag = this.KnapsackSimplified_OverlappedSubPromblems_OptimalSubstructure(weights,
                    w - weights[i_weights_index], i_rowIndexOfCache - 1);
                DP_Memoization_Cache[i_rowIndexOfCache][w] = flag;
            }
            return flag;
        }

<强>,其中

public bool KnapsackSimplified_DP_Memoization_Lazy(int[] weights, int W)
        {
            this.Validate(weights, W);
            //note 'row' index represents the number of weights been used
            //note 'colum' index represents the weight that can be achived using given 
            //number of weights 'row'
            bool?[][] DP_Memoization_Cache = new bool?[weights.Length+1][];
            for(int i = 0; i<=weights.Length; i++)
            {
                DP_Memoization_Cache[i] = new bool?[W + 1];
                for(int w=0; w<=W; w++)
                {
                    if(i != 0)
                    {
                        DP_Memoization_Cache[i][w] = null;
                    }
                    else
                    {
                        //can't get to weight 'w' using none of the given weights
                        DP_Memoization_Cache[0][w] = false;
                    }
                }
                DP_Memoization_Cache[i][0] = false;
            }
            bool f = this.KnapsackSimplified_DP_Memoization_Lazy(
                weights, w: W, i_rowIndexOfCache: weights.Length, DP_Memoization_Cache: DP_Memoization_Cache);
            Assert.IsTrue(f == DP_Memoization_Cache[weights.Length][W]);
            return f;
        }

版本3 识别重叠的子问题和最佳子结构

/// <summary>
        /// f(i, w) = False if i < 0
        ///           OR True if weights[i] == w
        ///           OR f(i-1, w) if weights[i] > w
        ///           OR f(i-1, w) || f(i-1, w-weights[i])
        /// </summary>
        public bool KnapsackSimplified_OverlappedSubPromblems_OptimalSubstructure(int[] weights, int W, int i)
        {
            if(i<0)
            {
                //no more weights to traverse
                return false;
            }
            if(weights[i] == W)
            {
                //we can just use current weight, so no need to call other recursive methods
                //just return true
                return true;
            }
            //see if W, can be achieved without using weights[i]
            bool flag = this.KnapsackSimplified_OverlappedSubPromblems_OptimalSubstructure(weights,
                W, i - 1);
            if(flag)
            {
                return true;
            }
            if(W > weights[i])
            {
                //see if W-weight[i] can be achieved with rest of the weights
                return this.KnapsackSimplified_OverlappedSubPromblems_OptimalSubstructure(weights, W - weights[i], i - 1);
            }
            return false;
        }

其中

public bool KnapsackSimplified_OverlappedSubPromblems_OptimalSubstructure(int[] weights, int W)
        {
            this.Validate(weights, W);
            bool f = this.KnapsackSimplified_OverlappedSubPromblems_OptimalSubstructure(weights, W,
                i: weights.Length - 1);
            return f;
        }

第4版暴力

private bool KnapsackSimplifiedProblemRecursive(int[] weights, int sum, int currentSum, int index, List<int> itemsInTheKnapsack)
        {
            if (currentSum == sum)
            {
                return true;
            }
            if (currentSum > sum)
            {
                return false;
            }
            if (index >= weights.Length)
            {
                return false;
            }
            itemsInTheKnapsack.Add(weights[index]);
            bool flag = KnapsackSimplifiedProblemRecursive(weights, sum, currentSum: currentSum + weights[index],
                index: index + 1, itemsInTheKnapsack: itemsInTheKnapsack);
            if (!flag)
            {
                itemsInTheKnapsack.Remove(weights[index]);
                flag = KnapsackSimplifiedProblemRecursive(weights, sum, currentSum, index + 1, itemsInTheKnapsack);
            }
            return flag;
        }
        public bool KnapsackRecursive(int[] weights, int sum, out List<int> knapsack)
        {
            if(sum <= 0)
            {
                throw new ArgumentException("sum should be +ve non zero integer");
            }
            knapsack = new List<int>();
            bool fits = KnapsackSimplifiedProblemRecursive(weights, sum, currentSum: 0, index: 0, 
                itemsInTheKnapsack: knapsack);
            return fits;
        }

版本5:使用堆栈的迭代版本(注意 - 相同的复杂性 - 使用堆栈 - 删除尾部递归)

public bool KnapsackIterativeUsingStack(int[] weights, int sum, out List<int> knapsack)
        {
            sum.Throw("sum", s => s <= 0);
            weights.ThrowIfNull("weights");
            weights.Throw("weights", w => (w.Length == 0)
                                  || w.Any(wi => wi < 0));
            var knapsackIndices = new List<int>();
            knapsack = new List<int>();
            Stack<KnapsackStackNode> stack = new Stack<KnapsackStackNode>();
            stack.Push(new KnapsackStackNode() { sumOfWeightsInTheKnapsack = 0, nextItemIndex = 1 });
            stack.Push(new KnapsackStackNode() { sumOfWeightsInTheKnapsack = weights[0], nextItemIndex = 1, includesItemAtCurrentIndex = true });
            knapsackIndices.Add(0);

            while(stack.Count > 0)
            {
                var top = stack.Peek();
                if(top.sumOfWeightsInTheKnapsack == sum)
                {
                    int count = 0;
                    foreach(var index in knapsackIndices)
                    {
                        var w = weights[index];
                        knapsack.Add(w);
                        count += w;
                    }
                    Debug.Assert(count == sum);
                    return true;
                }
                //basically either of the below three cases, we dont need to traverse/explore adjuscent
                // nodes further
                if((top.nextItemIndex == weights.Length) //we reached end, no need to traverse
                    || (top.sumOfWeightsInTheKnapsack > sum) // last added node should not be there
                    || (top.alreadyExploredAdjuscentItems)) //already visted
                {
                    if (top.includesItemAtCurrentIndex)
                    {
                        Debug.Assert(knapsackIndices.Contains(top.nextItemIndex - 1));
                        knapsackIndices.Remove(top.nextItemIndex - 1);
                    }
                    stack.Pop();
                    continue;
                }

                var node1 = new KnapsackStackNode();
                node1.sumOfWeightsInTheKnapsack = top.sumOfWeightsInTheKnapsack;
                node1.nextItemIndex = top.nextItemIndex + 1;
                stack.Push(node1);

                var node2 = new KnapsackStackNode();
                knapsackIndices.Add(top.nextItemIndex);
                node2.sumOfWeightsInTheKnapsack = top.sumOfWeightsInTheKnapsack + weights[top.nextItemIndex];
                node2.nextItemIndex = top.nextItemIndex + 1;
                node2.includesItemAtCurrentIndex = true;
                stack.Push(node2);

                top.alreadyExploredAdjuscentItems = true;
            }
            return false;
        }

其中

class KnapsackStackNode
        {
            public int sumOfWeightsInTheKnapsack;
            public int nextItemIndex;
            public bool alreadyExploredAdjuscentItems;
            public bool includesItemAtCurrentIndex;
        }

和单元测试

[TestMethod]
        public void KnapsackSimpliedProblemTests()
        {
            int[] weights = new int[] { 7, 5, 4, 4, 1 };
            List<int> bag = null;
            bool flag = this.KnapsackSimplifiedProblemIterativeUsingStack(weights, 10, knapsack: out bag);
            Assert.IsTrue(flag);
            Assert.IsTrue(bag.Contains(5));
            Assert.IsTrue(bag.Contains(4));
            Assert.IsTrue(bag.Contains(1));
            Assert.IsTrue(bag.Count == 3);
            flag = this.KnapsackSimplifiedProblemIterativeUsingStack(weights, 3, knapsack: out bag);
            Assert.IsFalse(flag);
            flag = this.KnapsackSimplifiedProblemIterativeUsingStack(weights, 7, knapsack: out bag);
            Assert.IsTrue(flag);
            Assert.IsTrue(bag.Contains(7));
            Assert.IsTrue(bag.Count == 1);
            flag = this.KnapsackSimplifiedProblemIterativeUsingStack(weights, 1, knapsack: out bag);
            Assert.IsTrue(flag);
            Assert.IsTrue(bag.Contains(1));
            Assert.IsTrue(bag.Count == 1);

            flag = this.KnapsackSimplified_DP_Tabulated_Eager(weights, 10);
            Assert.IsTrue(flag);
            flag = this.KnapsackSimplified_DP_Tabulated_Eager(weights, 3);
            Assert.IsFalse(flag);
            flag = this.KnapsackSimplified_DP_Tabulated_Eager(weights, 7);
            Assert.IsTrue(flag);
            flag = this.KnapsackSimplified_DP_Tabulated_Eager(weights, 1);
            Assert.IsTrue(flag);

            flag = this.KnapsackSimplified_DP_Memoization_Lazy(weights, 10);
            Assert.IsTrue(flag);
            flag = this.KnapsackSimplified_DP_Memoization_Lazy(weights, 3);
            Assert.IsFalse(flag);
            flag = this.KnapsackSimplified_DP_Memoization_Lazy(weights, 7);
            Assert.IsTrue(flag);
            flag = this.KnapsackSimplified_DP_Memoization_Lazy(weights, 1);
            Assert.IsTrue(flag);

            flag = this.KnapsackSimplified_OverlappedSubPromblems_OptimalSubstructure(weights, 10);
            Assert.IsTrue(flag);
            flag = this.KnapsackSimplified_OverlappedSubPromblems_OptimalSubstructure(weights, 3);
            Assert.IsFalse(flag);
            flag = this.KnapsackSimplified_OverlappedSubPromblems_OptimalSubstructure(weights, 7);
            Assert.IsTrue(flag);
            flag = this.KnapsackSimplified_OverlappedSubPromblems_OptimalSubstructure(weights, 1);
            Assert.IsTrue(flag);


            flag = this.KnapsackRecursive(weights, 10, knapsack: out bag);
            Assert.IsTrue(flag);
            Assert.IsTrue(bag.Contains(5));
            Assert.IsTrue(bag.Contains(4));
            Assert.IsTrue(bag.Contains(1));
            Assert.IsTrue(bag.Count == 3);
            flag = this.KnapsackRecursive(weights, 3, knapsack: out bag);
            Assert.IsFalse(flag);
            flag = this.KnapsackRecursive(weights, 7, knapsack: out bag);
            Assert.IsTrue(flag);
            Assert.IsTrue(bag.Contains(7));
            Assert.IsTrue(bag.Count == 1);
            flag = this.KnapsackRecursive(weights, 1, knapsack: out bag);
            Assert.IsTrue(flag);
            Assert.IsTrue(bag.Contains(1));
            Assert.IsTrue(bag.Count == 1);

            weights = new int[] { 11, 8, 7, 6, 5 };
            flag = this.KnapsackSimplifiedProblemIterativeUsingStack(weights, 20, knapsack: out bag);
            Assert.IsTrue(bag.Contains(8));
            Assert.IsTrue(bag.Contains(7));
            Assert.IsTrue(bag.Contains(5));
            Assert.IsTrue(bag.Count == 3);
            flag = this.KnapsackSimplifiedProblemIterativeUsingStack(weights, 27, knapsack: out bag);
            Assert.IsFalse(flag);
            flag = this.KnapsackSimplifiedProblemIterativeUsingStack(weights, 11, knapsack: out bag);
            Assert.IsTrue(flag);
            Assert.IsTrue(bag.Contains(11));
            Assert.IsTrue(bag.Count == 1);
            flag = this.KnapsackSimplifiedProblemIterativeUsingStack(weights, 5, knapsack: out bag);
            Assert.IsTrue(flag);
            Assert.IsTrue(bag.Contains(5));
            Assert.IsTrue(bag.Count == 1);

            flag = this.KnapsackRecursive(weights, 20, knapsack: out bag);
            Assert.IsTrue(bag.Contains(8));
            Assert.IsTrue(bag.Contains(7));
            Assert.IsTrue(bag.Contains(5));
            Assert.IsTrue(bag.Count == 3);
            flag = this.KnapsackRecursive(weights, 27, knapsack: out bag);
            Assert.IsFalse(flag);
            flag = this.KnapsackRecursive(weights, 11, knapsack: out bag);
            Assert.IsTrue(flag);
            Assert.IsTrue(bag.Contains(11));
            Assert.IsTrue(bag.Count == 1);
            flag = this.KnapsackRecursive(weights, 5, knapsack: out bag);
            Assert.IsTrue(flag);
            Assert.IsTrue(bag.Contains(5));
            Assert.IsTrue(bag.Count == 1);
        }

答案 3 :(得分:2)

这是一个简单的递归实现(效率不高,但很容易理解)。它是在Python中,OP要求Java实现,但将其移植到Java应该不会太困难,就像查看伪代码一样。

main函数声明三个参数:V是值数组,W是权重数组,C是背包的容量。

def knapsack(V, W, C):
    return knapsack_aux(V, W, len(V)-1, C)

def knapsack_aux(V, W, i, aW):
    if i == -1 or aW == 0:
        return 0
    elif W[i] > aW:
        return knapsack_aux(V, W, i-1, aW)
    else:
        return max(knapsack_aux(V, W, i-1, aW),
                   V[i] + knapsack_aux(V, W, i-1, aW-W[i]))

算法最大化添加到背包中的项目的值,返回给定权重可达到的最大值

答案 4 :(得分:2)

public class Knapsack {
    public int[] arr = {11,8,7,6,5};
    public int[] retArr = new int[5];
    int i = 0;
    public boolean problem(int sum, int pick) {
        if(pick == arr.length) {
            return false;
        }
        if(arr[pick] < sum) {   
            boolean r = problem(sum - arr[pick], pick+1);           
            if(!r) {
                return problem(sum, pick+1);
            } else {
                retArr[i++] = arr[pick];
                return true;
            }                   
        } else if (arr[pick] > sum) {
            return problem(sum, pick+1);
        } else {
            retArr[i++] = arr[pick];
            return true;
        }
    }

    public static void main(String[] args) {
        Knapsack rk = new Knapsack`enter code here`();
        if(rk.problem(20, 0)) {
            System.out.println("Success " );
            for(int i=0; i < rk.retArr.length; i++)
                System.out.println(rk.retArr[i]);
        }
    }

}

答案 5 :(得分:0)

Java中的另一个动态编程实现。 我总觉得使用备忘录的自上而下的DP比自下而上的DP更容易理解。

完整,不言自明,可运行的代码,使用this example from Wikipedia中的数据:

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

public class Knapsack {

    private static final List<Item> ITEMS = new ArrayList<>();
    private static final Map<Integer, Bag> CACHE = new HashMap<>();
    private static final boolean FINITE_ITEMS = true; //whether an item can be added more than once

    public static void main(String[] args) {
        ITEMS.add(new Item(4, 12, "GREEN"));
        ITEMS.add(new Item(2, 2, "CYAN"));
        ITEMS.add(new Item(2, 1, "GREY"));
        ITEMS.add(new Item(1, 1, "ORANGE"));
        ITEMS.add(new Item(10, 4, "YELLOW"));
        Bag best = bestBagForCapa(15);
        System.out.println(best.toString());
    }

    public static Bag bestBagForCapa(int capa) {
        if (CACHE.containsKey(capa)) return CACHE.get(capa);
        if (capa < 0) return null;
        if (capa == 0) return new Bag(0, 0);

        int currentWeight = -1;
        int currentValue = -1;
        String newItem = null;
        List<String> previousItems = null;
        for (Item p : ITEMS) {
            Bag previous = bestBagForCapa(capa - p.weight);
            if (previous == null) continue;

            int weightSoFar = previous.weight;
            int valueSoFar = previous.value;
            int nextBestValue = 0;
            Item candidateItem = null;
            for (Item candidate : ITEMS) {
                if (FINITE_ITEMS && previous.alreadyHas(candidate)) continue;
                if (weightSoFar + candidate.weight <= capa && nextBestValue < valueSoFar + candidate.value) {
                    candidateItem = candidate;
                    nextBestValue = valueSoFar + candidate.value;
                }
            }

            if (candidateItem != null && nextBestValue > currentValue) {
                currentValue = nextBestValue;
                currentWeight = weightSoFar + candidateItem.weight;
                newItem = candidateItem.name;
                previousItems = previous.contents;
            }
        }

        if (currentWeight <= 0 || currentValue <= 0) throw new RuntimeException("cannot be 0 here");
        Bag bestBag = new Bag(currentWeight, currentValue);
        bestBag.add(previousItems);
        bestBag.add(Collections.singletonList(newItem));
        CACHE.put(capa, bestBag);
        return bestBag;
    }

}

class Item {

    int value;
    int weight;
    String name;

    Item(int value, int weight, String name) {
        this.value = value;
        this.weight = weight;
        this.name = name;
    }

}

class Bag {

    List<String> contents = new ArrayList<>();
    int weight;
    int value;

    boolean alreadyHas(Item item) {
        return contents.contains(item.name);
    }

    @Override
    public String toString() {
        return "weight " + weight + " , value " + value + "\n" + contents.toString(); 
    }

    void add(List<String> name) {
        contents.addAll(name);
    }

    Bag(int weight, int value) {
        this.weight = weight;
        this.value = value;
    }

}

答案 6 :(得分:0)

def knpsack(weight , value , k , index=0 , currweight=0):
    if(index>=len(weight)):
        return 0
take = 0
dontake = 0
if(currweight+weight[index] <= k):
    take = value[index]  + 
         knpsack(weight,value,k,index+1,currweight+weight[index])
dontake = knpsack(weight,value,k,index+1,currweight)
return max(take,dontake)

答案 7 :(得分:-1)

这是一个Java解决方案

static int knapsack(int[] values, int[] weights, int W, int[] tab, int i) {
    if(i>=values.length) return 0;
    if(tab[W] != 0) 
        return tab[W];      

    int value1 = knapsack(values, weights, W, tab, i+1);        
    int value2 = 0;
    if(W >= weights[i]) value2 = knapsack(values, weights, W-weights[i], tab, i+1) + values[i];

    return tab[W] = (value1>value2) ? value1 : value2;
}

使用

进行测试
public static void main(String[] args) {
    int[] values = new int[] {894, 260, 392, 281, 27};
    int[] weights = new int[] {8, 6, 4, 0, 21};
    int W = 30;
    int[] tab = new int[W+1];
    System.out.println(knapsack(values, weights, W, tab, 0));
}

答案 8 :(得分:-1)

这是Java中的一个简单的递归解决方案,但如果可能的话,你应该避免使用递归。

public class Knapsack {

    public static void main(String[] args) {
        int[] arr = new int[]{11, 8, 7, 6, 5};
        find(arr,20);
    }

    public static boolean find( int[] arr,int total){
        return find(arr,0,total);
    }

    private static boolean find( int[] arr,int start,  int total){
        if (start == arr.length){
            return false;
        }
        int curr = arr[start];
        if (curr == total){
            System.out.println(curr);
            return true;
        }else if (curr > total || !find(arr,start+1,total-curr)){
            return find(arr,start+1,total);
        }
        System.out.println(curr);
        return true;
    }
}