递归背包Java

时间:2013-10-10 00:23:58

标签: java recursion knapsack-problem

我正在努力完成家庭作业,我相信我的解决方案过于复杂,并且需要任何愿意提供帮助的人的帮助。让我解释一下这项任务的基本规则。

以下是另一篇文章的链接,其中包含确切的问题信息。

How do I solve the 'classic' knapsack algorithm recursively?

将给出一组数字,例如:15,11,8,7,6,5。第一个数字总是对应于背包的目标或容量。我必须做的是递归检查所有数字,看看是否有任何数字加起来背包的容量。如果他们这样做,我将打印与目标总和相加的数字,然后继续检查其他可能的解决方案。在研究此问题时,大多数帖子都会解决一个解决方案。让我解释一下作业的基本规则。

这项任务必须以递归方式完成,没有例外。 必须找到所有解决方案 数字从最高到最低排序。

在15,11,8,7,6,5中只有一个8 + 7 + 5 = 15的解决方案。但是,给定数据集如15,10,9,8,7,6, 5,4,3,2存在多种解决方案,例如。

10 + 5 = 15
9 + 6 = 15
8 + 7 = 15

基本上有两个问题需要解决。

从上面链接的上一篇文章:

这个想法,鉴于你陈述的问题(指明我们必须使用递归)很简单:对于你可以采取的每个项目,看看是否更好地接受它。所以只有两条可能的道路 你带走了这个项目 你不接受它 当您取走该物品时,将其从列表中删除,然后按物品的重量减少容量。 如果您不接受该项目,则从列表中删除,但不会降低容量。


我在解决这个解决方案中的作者所说的内容时遇到了一些麻烦。

For example: Assuming a number set of 20, 11, 8, 7, 6,5
1. Target is 20
2. Read in number from set: 11
4. 11 < 20, Add 11 to solution
5. New target is 9 (20 - 11)
6. Read in the next number: 8
7. 8 is less than 9, Add 8 to solution
8. New target is 1 (20 - 19)
9 Read in 7, 7 is larger than 1, do not add 7

我无法理解的是,如果我不添加数字,该怎么办?

您拍摄的项目:您从列表中删除该项目并减少容量 你没有拿一个项目:你从列表中删除该项目,但你没有减少容量。

在我的代码中,在“take item”或“dont take item”的情况下,我不会从我的体重列表中删除一个项目,我认为这是我的问题。

我将发布一些我在下面为此作业编写过的代码。正如您所看到的,存在一个过于膨胀的解决方案,其效果不如真正的解决方案那么优雅。如果有人可以提供有关如何使用上述分配参数真正解决此问题的建议或见解,我将不胜感激。谢谢。

import java.io.PrintWriter;
import java.util.ArrayList;

import javax.swing.JOptionPane;


public class Knapsack
{
    public static void main(String[] args)
    {
        //Read in user input first

        int[] tempArray;

        String userInput = JOptionPane.showInputDialog("Enter a list of numbers delimited by a single space.");

        String[] splitElements = userInput.split("\\s+");

        //User array will contain the exact amount of 
        //numbers as long as extra spaces are not entered. 
        tempArray = new int[splitElements.length];

        for(int i = 0; i < tempArray.length; i++)
        {
            tempArray[i] = Integer.parseInt(splitElements[i]);
        }

        Recursion recObj = new Recursion(tempArray);

    }
}
class Recursion
{
    private int[] weightArray;
    private int [] solutionArray;
    private int counter;
    private int mainGoal;
    private int [] backupOfOriginal;
    private int solutionArrayCounter;
    private ArrayList numberList;
    private ArrayList previousSolutionsFound;
    private int passThrough;
    private int baseIterator;
    private ArrayList distinctSolutions;

    public Recursion(int[] paramArray)
    {
        weightArray = paramArray;
        backupOfOriginal = weightArray;
        solutionArray = new int[paramArray.length];
        //Start at index 1 where the first number technically starts. 
        counter = 0;
        //Keep track of main goal
        mainGoal = weightArray[0];

        solutionArrayCounter = 0;
        passThrough = 0;
        baseIterator = 0;
        distinctSolutions = new ArrayList();

        numberList = new ArrayList();
        previousSolutionsFound = new ArrayList();

        for(int i = 1; i < weightArray.length; i++)
        {
            numberList.add(weightArray[i]);
        }


        //Begin the recursive problem.
        CheckForSums(mainGoal, numberList);

    }

    public void CheckForSums(int targetValue, ArrayList weightArray)
    {
        int numberRead = (Integer) weightArray.get(counter);
        targetValue = ComputeTarget();

        counter++;

        //Base case if any number to read
        //is greater than the main target value
        //remove it
        if(numberRead > mainGoal)
        {
            weightArray.remove(counter);
            counter--;
        }

        if(numberRead <= targetValue)
        {
            AddToSolution(numberRead);
            CheckForPossibleSolution();
            //Add the item to the solution  
        }

        //counter++;

        if(counter == weightArray.size())
        {
            passThrough++;

            counter = passThrough + 1;
            RemoveOneFromSolution();    
        }

        //Advance forward one position
        if(passThrough == weightArray.size() - 1)
        {
            counter = 0;
            passThrough = 0;
            weightArray = RebuildArrayList(weightArray);

            for(int i = 0; i < baseIterator; i++)
            {
                weightArray.remove(0);
            }

            baseIterator++;

            ResetSolutionArray();
        }

        if(baseIterator == this.weightArray.length - 2)
        {
            //Should be completely done
            return;
        }

        CheckForSums(targetValue, weightArray);
    }

    public void ResetSolutionArray()
    {
        solutionArrayCounter = 0;

        for(int i = 0; i < solutionArray.length; i++)
        {
            solutionArray[i] = 0;
        }
    }

    public void CheckForPossibleSolution()
    {
        if(SumOfSolutionsFound() == mainGoal)
        {
            PrintFoundSolution();
            RemoveDownToBaseNumber();
        }

        else
        {
            System.out.println("No solution found yet.");
        }
    }

    public void RemoveOneFromSolution()
    {
        if(solutionArrayCounter > 1)
        {
            solutionArrayCounter--;
        }

        if(solutionArrayCounter > 1)
        {
            solutionArray[solutionArrayCounter] = 0;
        }
    }

    public void RemoveDownToBaseNumber()
    {
        while(solutionArrayCounter > 1)
        {
            solutionArrayCounter--;
            solutionArray[solutionArrayCounter] =0;
        }
    }

    public int SumOfSolutionsFound()
    {
        int sumOfSolutions = 0;

        for(int i = 0; i < solutionArray.length; i++)
        {
            sumOfSolutions += solutionArray[i];
        }
        return sumOfSolutions;
    }

    public ArrayList<Integer> RebuildArrayList(ArrayList<Integer> paramList)
    {
        paramList = new ArrayList();

        for(int i = 1; i < weightArray.length; i++)
        {
            paramList.add(weightArray[i]);
        }
        return paramList;
    }

    public void PrintFoundSolution()
    {
        StringBuilder toMessageBox = new StringBuilder();
        System.out.print("Found a solution! ");
        toMessageBox.append("Found a Solution! ");

        for(int i = 0; i < solutionArray.length; i++)
        {
            System.out.print(solutionArray[i] + " ");
            toMessageBox.append(solutionArray[i] + " ");
        }

        String finishedMessage = toMessageBox.toString();

        boolean displayCurrentSolution = true;

        for(int i = 0; i < previousSolutionsFound.size(); i++)
        {
            String previousSolution = previousSolutionsFound.get(i).toString();
            if(finishedMessage.equals(previousSolution))
            {
                displayCurrentSolution = false;
            }
        }

        previousSolutionsFound.add(finishedMessage);

        if(displayCurrentSolution == true)
        {
            distinctSolutions.add(finishedMessage);

            JOptionPane.showMessageDialog(null,  finishedMessage, 
                    "Solution for target: " + mainGoal, JOptionPane.INFORMATION_MESSAGE);
        }
    }




    public void AddToSolution(int value)
    {
        solutionArray[solutionArrayCounter] = value;
        solutionArrayCounter++;
    }

    public int ComputeTarget()
    {
        int sumOfSolutions = 0;

        for(int i = 0; i < solutionArray.length; i++)
        {
            sumOfSolutions += solutionArray[i];
        }

        int numbersNeededToReachMainGoal = mainGoal - sumOfSolutions;
        return numbersNeededToReachMainGoal;
    }
}

1 个答案:

答案 0 :(得分:1)

您描述的问题实际上是一种特殊情况,您只有物品权重,但没有利润 - 或者权重和利润相等。这个问题通常不被称为背包,而是Subset Sum的最大化版本。

此外,对于递归解决方案,除了输入之外不需要任何数组。

假设项目大小在数组weightArray(此处为零指数)中给出,长度为n,容量表示总容量可用。

定义(首先在概念上,而不是在代码中)函数

F( remainingCapacity, i ) :=
maximum total weight attainable for items
with indices in {0,..,i} of infinity if no such solution exists

请注意

F(容量,n - 1)

产生问题的解决方案。此外,F具有属性

F( remainingCapacity, -1 ) = 0 if remainingCapacity >= 0 

F( remainingCapacity, i ) =
Infinity (can be simulated by a sufficiently
large integer) if remainingCapacity < 0

F( remainingCapacity, i ) =
max( F( remainingCapacity - weightArray[ i ], i - 1 ),
     F( remainingCapacity, i - 1 ) )

其中最大表达式中的第一项对应于“取项目i”情况,而第二表达式对应于“不取项目i”情况。上述案例可以或多或少地轻易转变为实际实施。

但是请注意,这只会产生一个项目选择可达到的最大值,而不是项目本身的实际选择。