public Bag fillBag(ProblemInstance problemInstance) {

        if(problemInstance == null){
            throw new IllegalArgumentException("Parameter problemInstance is null");
        }

        initialFill(problemInstance.getItems(), problemInstance.getMaxBagWeight());
        long bestBagValue = getBagValue(this.bestBag, itemValues);

        int[] currentBag = new int[problemInstance.getItems().size()];
        copyArrayValues(this.bestBag, currentBag);

        long currentBagValue = bestBagValue;
        long currentBagWeight = getBagWeight(currentBag, itemWeights);
        long extendedBagValue = 0;
        long maxBagWeight = problemInstance.getMaxBagWeight();

        boolean doProcessing = true;
        while (doProcessing) {

            int lastNonZeroPosition = lastNonZeroPosition(currentBag);

            reduceBag(currentBag, lastNonZeroPosition);
            currentBagValue = getBagValue(currentBag,itemValues);
            currentBagWeight = getBagWeight(currentBag,itemWeights);

            //After reduction a bound is calculated to check if an extension
            //would make sense. If not the branch is skipped.
            if ((lastNonZeroPosition + 1) < problemInstance.getItems().size()) {

                float bound = (maxBagWeight - currentBagWeight) * itemValuePerUnit[lastNonZeroPosition + 1];
                if (currentBagValue + bound > bestBagValue) {
                    extendBag(currentBag, itemWeights, maxBagWeight, lastNonZeroPosition);
                    extendedBagValue = getBagValue(currentBag, itemValues);
                }
            }

            //Check if a better solution was found
            if (extendedBagValue > bestBagValue) {

                copyArrayValues(currentBag, bestBag);
                bestBagValue = extendedBagValue;
                currentBagValue = extendedBagValue;
                currentBagWeight = getBagWeight(currentBag, itemWeights);
            }

            //Check if the input was completely reduced,
            //if yes no further processing needs to be done
            if (isBagEmpty(currentBag)) {
                doProcessing = false;
            }
        }

        //fill resultBag
        Bag bag = new Bag(maxBagWeight);
        for (int i = 0; i < bestBag.length; i++) {
            for (int j = 0; j < bestBag[i]; j++) {
                Item currentItem = problemInstance.getItems().get(i);
                bag.addItem(currentItem);
            }
        }

        return bag;
    }