简体   繁体   中英

Printing Knapsack items (Repetition of items allowed)

I implemented 2 ways to solve knapsack, but i cant print the selected items in 1 way and the other one doesnt really work well because it misses my first item values. Baiscally, my knapsack problem is dividing a bar of lenght N, in sub-bars of lenght 1,2,...., N where each sub-bar has different costs.

The repetition of items is allowed as soon as you dont exceed lenght of course. So: 1) I have a bar of lenght N, which can be divided. Each division from 1 to N has a price related. 2) Knapsack to find the max profit, where it is possible to take multiple times the same item. 3)Printing the elements selected by Knapsack.

My problems are: 1) In the first piece of code, i cant understand how to print the chosen items. 2)I tried the matrix approach , but i can't understand how to set the Knapsack matrix's equations with repetition of items allowed.

This is my first try, this actually works and gives me the proper answer, but i cant really understand how i can print the chosen items.

int *k = malloc(sizeof(int ) * lenght+1);
for( i = 0 ; i <= lenght; i++) k[i] = 0;

Filling knapsack array.

for(i = 0 ; i <= lenght ; i++){
    for(w = 0 ; w < lenght ; w++){
        if( bar[w] <= i){
            k[i] = searchmax( prices[w] + k[i-bar[w]] , k[i] );
        } 
    }
}

This is my second approach, which doesnt works, but i have much more clear how to print the items after, because it works with classic knapsack.

int **k = malloc(sizeof(int*) * (lenght+1));
for(i=0;i<=lenght;i++) k[i] = malloc(sizeof(int)*(lenght+1));

for( i = 0 ; i <= lenght; i++)k[0][i]= 0;
for(i = 0 ; i <=lenght;i++) k[i][0]=0;

for(i=1;i<=lenght;i++){
    for(w=1;w<=lenght;w++){
        if(bar[i]<=w){
            printf("\nPrices: %d  Barlenght: %d" , prices[i], bar[i]);
            k[i][w]=searchmax(prices[i]+k[i][w-bar[i]], k[i-1][w]);
        }
        else k[i][w] = k[i-1][w];

    }
}

The result with this set of inputs: Lenght of bar:4

Prices for sub-bar of lenght 1 to N, where N in this case is 4, is : 1, 5, 8, 9.

Should be : Profit: 10 ,Items: 2 , 2

You should print the element only if it is 'kept in the knapsack'. With each iteration, you check whether to put an element in the knapsack or to discard it. In your code, you should check this: if a element 'is kept in the knapsack', print it and its weight, along with other values ​​that were already in the knapsack and that when adding this element do not exceed the capacity of the knapsack. There are several ways to do this. I thought about this: while executing the method, save the selected values ​​in the knapsack for each possible capacity of it (if it has capacity W, you would have to store the selected values ​​in a matrix, where each line w represents a value 0 <= w <= W) and the columns contain the elements of the knapsack with a certain capacity. I implemented a solution using C++. If you don't understand any part, tell me I can explain.

Code

#include <iostream>
#include <vector>
#include <algorithm>
#include <stdexcept>
#include <string>


/**
* Responsible for dealing with the unbounded knapsack problem.
*/
class UnboundedKnapsack
{
    //-------------------------------------------------------------------------
    //      Attributes
    //-------------------------------------------------------------------------
    /**
    * Stores maximum value of the knapsack for a certain capacity.
    */
    std::vector<int> knapsack;

    /**
    * Stores elements that are part of the knapsack with a certain capacity.
    * <li><b>Line:</b> Knapsack capacity</li>
    * <li><b>Column:</b> Elements</li>
    */
    std::vector<std::vector<int> > selectedElements;

    /**
    * Stores maximum knapsack capacity.
    */
    int maximumCapacity;


public:
    //-------------------------------------------------------------------------
    //      Constructor
    //-------------------------------------------------------------------------
    UnboundedKnapsack()
    {
        maximumCapacity = -1;
    }


    //-------------------------------------------------------------------------
    //      Destructor
    //-------------------------------------------------------------------------
    ~UnboundedKnapsack()
    {
        delete this;
    }


    //-------------------------------------------------------------------------
    //      Methods
    //-------------------------------------------------------------------------
    /**
    * Unbounded knapsack allows to use one or more occurrences of an item.
    *
    * @param        w Weight of the elements
    * @param        v Value of the elements
    * @param        N Number of itens
    * @param        W Maximum weight capacity
    * @return       This object to allow chained calls
    */
    UnboundedKnapsack* knapsack_unbounded(std::vector<int>& w, std::vector<int>& v, int N, int W)
    {
        // Stores the maximum value which can be reached with a certain capacity
        knapsack.clear();
        knapsack.resize(W + 1);

        maximumCapacity = W + 1;

        // Stores selected elements with a certain capacity
        selectedElements.resize(W + 1);

        // Initializes maximum value vector with zero
        for (int i = 0; i < W + 1; i++) {
            knapsack[i] = 0;
        }

        // Computes the maximum value that can be reached for each capacity
        for (int capacity = 0; capacity < W + 1; capacity++) {
            // Goes through all the elements
            for (int n = 0; n < N; n++) {
                if (w[n] <= capacity) {
                    // max(knapsack[capacity], knapsack[capacity - w[n]] + v[n])
                    if (knapsack[capacity] <= knapsack[capacity - w[n]] + v[n]) {
                        knapsack[capacity] = knapsack[capacity - w[n]] + v[n];

                        // Stores selected elements
                        selectedElements[capacity].clear();
                        selectedElements[capacity].push_back(n + 1);

                        for (int elem : selectedElements[capacity - w[n]]) {
                            selectedElements[capacity].push_back(elem);
                        }
                    }
                }
            }
        }

        return this;
    }

    /**
    * Returns maximum value for a certain number of elements and a certain
    * capacity.
    *
    * @param        capacity Capacity of the knapsack
    * @return       Maximum possible value with capacity provided
    * @throws       std::invalid_argument If capacity provided is out of bounds
    */
    int getMaximumValue(int capacity)
    {
        if (capacity < 0 || capacity >= maximumCapacity)
            throw std::invalid_argument("Capacity out of bounds");

        return knapsack[capacity];
    }

    /**
    * Returns elements that belong to the knapsack with a certain capacity.
    *
    * @param        capacity Capacity of the knapsack
    * @return       Elements that are part of the knapsack with the capacity
    * provided
    * @throws       std::invalid_argument If capacity provided is out of bounds
    * @apiNote      Elements are referenced by their index + 1
    */
    std::vector<int>& getSelectedElements(int capacity)
    {
        if (capacity < 0 || capacity >= maximumCapacity)
            throw std::invalid_argument("Capacity out of bounds");

        return selectedElements[capacity];
    }

    /**
    * Returns elements that are part of the knapsack with a certain capacity.
    * This method will return a {@link std::string} with the following format:
    * <code>[elem1, elem2, elem3...]</code>
    *
    * @param        capacity Capacity of the knapsack
    * @return       Elements that are part of the knapsack with the capacity
    * provided
    * @apiNote      Elements are referenced by their index + 1
    */
    std::string selectedElements_toString(int capacity)
    {
        std::string response = "[";

        for (int element : selectedElements[capacity]) {
            response.append(std::to_string(element));
            response.append(", ");
        }

        // Removes last ", "
        response.pop_back();
        response.pop_back();

        response.append("]");

        return response;
    }
};


//-------------------------------------------------------------------------
//      Main
//-------------------------------------------------------------------------
/**
* Example made based on this exercise:
* {@link https://www.urionlinejudge.com.br/repository/UOJ_1487_en.html}
*/
int main()
{
    UnboundedKnapsack* knapsack = new UnboundedKnapsack();
    int totalCapacity = 60, elements = 5;
    std::vector<int> elements_weight = { 10, 20, 5, 50, 22 };
    std::vector<int> elements_values = { 30, 32, 4, 90, 45 };

    knapsack->knapsack_unbounded(elements_weight, elements_values, elements, totalCapacity);

    std::cout << "Maximum value: "
        << knapsack->getMaximumValue(totalCapacity)
        << std::endl;
    std::cout << "Selected elements: "
        << knapsack->selectedElements_toString(totalCapacity)
        << std::endl;

    system("pause");

    return 0;
}

Output

Maximum value: 180
Selected elements: [1, 1, 1, 1, 1, 1]

I hope this helps. In case you are interested, I also implemented a version that displays the elements stored with the classic version of the knapsack. It is available here: https://github.com/williamniemiec/algorithms/blob/master/Dynamic%20programming/knapsack/c%2B%2B/BoundedKnapsack.cpp

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM