Task: Knapsack problem_Bounded


C++: #include <iostream>
#include <vector>
#include <algorithm>
#include <stdexcept>
#include <memory>
#include <sys/time.h>

using std::cout;
using std::endl;

class StopTimer
{
public:
    StopTimer(): begin_(getUsec()) {}
    unsigned long long getTime() const { return getUsec() - begin_; }
private:
    static unsigned long long getUsec()
    {
        timeval tv;
        const int res = ::gettimeofday(&tv, 0);
        if(res)
            return 0;
        return tv.tv_usec + 1000000 * tv.tv_sec;
    }
    unsigned long long begin_;
};

struct KnapsackTask
{
    struct Item
    {
        std::string name;
        unsigned w, v, qty;
        Item(): w(), v(), qty() {}
        Item(const std::string& iname, unsigned iw, unsigned iv, unsigned iqty):
            name(iname), w(iw), v(iv), qty(iqty)
        {}
    };
    typedef std::vector<Item> Items;
    struct Solution
    {
        unsigned v, w;
        unsigned long long iterations, usec;
        std::vector<unsigned> n;
        Solution(): v(), w(), iterations(), usec() {}
    };
    
    KnapsackTask(): maxWeight_(), totalWeight_() {}
    void add(const Item& item)
    {
        const unsigned totalItemWeight = item.w * item.qty;
        if(const bool invalidItem = !totalItemWeight)
            throw std::logic_error("Invalid item: " + item.name);
        totalWeight_ += totalItemWeight;
        items_.push_back(item);
    }
    const Items& getItems() const { return items_; }
    void setMaxWeight(unsigned maxWeight) { maxWeight_ = maxWeight; }
    unsigned getMaxWeight() const { return std::min(totalWeight_, maxWeight_); }

private:
    unsigned maxWeight_, totalWeight_;
    Items items_;
};

class BoundedKnapsackRecursiveSolver
{
public:
    typedef KnapsackTask Task;
    typedef Task::Item Item;
    typedef Task::Items Items;
    typedef Task::Solution Solution;

    void solve(const Task& task)
    {
        Impl(task, solution_).solve();
    }
    const Solution& getSolution() const { return solution_; }
private:
    class Impl
    {
        struct Candidate
        {
            unsigned v, n;
            bool visited;
            Candidate(): v(), n(), visited(false) {}
        };
        typedef std::vector<Candidate> Cache;
    public:
        Impl(const Task& task, Solution& solution):
            items_(task.getItems()),
            maxWeight_(task.getMaxWeight()),
            maxColumnIndex_(task.getItems().size() - 1),
            solution_(solution),
            cache_(task.getMaxWeight() * task.getItems().size()),
            iterations_(0)
        {}
        void solve()
        {
            if(const bool nothingToSolve = !maxWeight_ || items_.empty())
                return;
            StopTimer timer;
            Candidate candidate;
            solve(candidate, maxWeight_, items_.size() - 1);
            convertToSolution(candidate);
            solution_.usec = timer.getTime();
        }
    private:
        void solve(Candidate& current, unsigned reminderWeight, const unsigned itemIndex)
        {
            ++iterations_;

            const Item& item(items_[itemIndex]);

            if(const bool firstColumn = !itemIndex)
            {
                const unsigned maxQty = std::min(item.qty, reminderWeight/item.w);
                current.v = item.v * maxQty;
                current.n = maxQty;
                current.visited = true;
            }
            else
            {
                const unsigned nextItemIndex = itemIndex - 1;
                {
                    Candidate& nextItem = cachedItem(reminderWeight, nextItemIndex);
                    if(!nextItem.visited)
                        solve(nextItem, reminderWeight, nextItemIndex);
                    current.visited = true;
                    current.v = nextItem.v;
                    current.n = 0;
                }
                if(reminderWeight >= item.w)
                {
                    for (unsigned numberOfItems = 1; numberOfItems <= item.qty; ++numberOfItems)
                    {
                        reminderWeight -= item.w;
                        Candidate& nextItem = cachedItem(reminderWeight, nextItemIndex);
                        if(!nextItem.visited)
                            solve(nextItem, reminderWeight, nextItemIndex);

                        const unsigned checkValue = nextItem.v + numberOfItems * item.v;
                        if ( checkValue > current.v)
                        {
                            current.v = checkValue;
                            current.n = numberOfItems;
                        }
                        if(!(reminderWeight >= item.w))
                            break;
                    }
                }
            }
        }
        void convertToSolution(const Candidate& candidate)
        {
            solution_.iterations = iterations_;
            solution_.v = candidate.v;
            solution_.n.resize(items_.size());

            const Candidate* iter = &candidate;
            unsigned weight = maxWeight_, itemIndex = items_.size() - 1;
            while(true)
            {
                const unsigned currentWeight = iter->n * items_[itemIndex].w;
                solution_.n[itemIndex] = iter->n;
                weight -= currentWeight;
                if(!itemIndex--)
                    break;
                iter = &cachedItem(weight, itemIndex);
            }
            solution_.w = maxWeight_ - weight;
        }
        Candidate& cachedItem(unsigned weight, unsigned itemIndex)
        {
            return cache_[weight * maxColumnIndex_ + itemIndex];
        }
        const Items& items_;
        const unsigned maxWeight_;
        const unsigned maxColumnIndex_;
        Solution& solution_;
        Cache cache_;
        unsigned long long iterations_;
    };
    Solution solution_;
};

void populateDataset(KnapsackTask& task)
{
    typedef KnapsackTask::Item Item;
    task.setMaxWeight( 400 );
    task.add(Item("map",9,150,1));
    task.add(Item("compass",13,35,1));
    task.add(Item("water",153,200,2));
    task.add(Item("sandwich",50,60,2));
    task.add(Item("glucose",15,60,2));
    task.add(Item("tin",68,45,3));
    task.add(Item("banana",27,60,3));
    task.add(Item("apple",39,40,3));
    task.add(Item("cheese",23,30,1));
    task.add(Item("beer",52,10,3));
    task.add(Item("suntancream",11,70,1));
    task.add(Item("camera",32,30,1));
    task.add(Item("T-shirt",24,15,2));
    task.add(Item("trousers",48,10,2));
    task.add(Item("umbrella",73,40,1));
    task.add(Item("w-trousers",42,70,1));
    task.add(Item("w-overclothes",43,75,1));
    task.add(Item("note-case",22,80,1));
    task.add(Item("sunglasses",7,20,1));
    task.add(Item("towel",18,12,2));
    task.add(Item("socks",4,50,1));
    task.add(Item("book",30,10,2));
}

int main()
{
    KnapsackTask task;
    populateDataset(task);

    BoundedKnapsackRecursiveSolver solver;
    solver.solve(task);
    const KnapsackTask::Solution& solution = solver.getSolution();

    cout << "Iterations to solve: " << solution.iterations << endl;
    cout << "Time to solve: " << solution.usec << " usec" << endl;
    cout << "Solution:" << endl;
    for (unsigned i = 0; i < solution.n.size(); ++i)
    {
        if (const bool itemIsNotInKnapsack = !solution.n[i])
            continue;
        cout << "  " << solution.n[i] << ' ' << task.getItems()[i].name << " ( item weight = " << task.getItems()[i].w << " )" << endl;
    }

    cout << "Weight: " << solution.w << " Value: " << solution.v << endl;
    return 0;
}


C#: using System;  
class program
{
    static void Main()
    {
        knapSack(40);
        var sw = System.Diagnostics.Stopwatch.StartNew();
        Console.Write(knapSack(400) + "\n" + sw.Elapsed);  
        Console.Read();
    }

    static string knapSack(uint w1)
    {
        init(); change();
        uint n = (uint)w.Length; var K = new uint[n + 1, w1 + 1];
        for (uint vi, wi, w0, x, i = 0; i < n; i++)
            for (vi = v[i], wi = w[i], w0 = 1; w0 <= w1; w0++)
            {
                x = K[i, w0];
                if (wi <= w0) x = max(vi + K[i, w0 - wi], x);
                K[i + 1, w0] = x;
            }
        string str = "";
        for (uint v1 = K[n, w1]; v1 > 0; n--)
            if (v1 != K[n - 1, w1])
            {
                v1 -= v[n - 1]; w1 -= w[n - 1]; str += items[n - 1] + "\n";
            }
        return str;
    }

    static uint max(uint a, uint b) { return a > b ? a : b; }

    static byte[] w, v; static string[] items;

    static byte[] p = { 1, 1, 2, 2, 2, 3, 3, 3, 1, 3, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2 };

    static void init()
    {
        w = new byte[] { 9, 13, 153, 50, 15, 68, 27, 39, 23, 52, 11,
                          32, 24, 48, 73, 42, 43, 22, 7, 18, 4, 30 };

        v = new byte[] { 150, 35, 200, 60, 60, 45, 60, 40, 30, 10, 70,
                          30, 15, 10, 40, 70, 75, 80, 20, 12, 50, 10 };

        items = new string[] {"map","compass","water","sandwich","glucose","tin",
                              "banana","apple","cheese","beer","suntan cream",
                              "camera","T-shirt","trousers","umbrella",
                              "waterproof trousers","waterproof overclothes",
                              "note-case","sunglasses","towel","socks","book"};
    }

    static void change()
    {
        int n = w.Length, s = 0, i, j, k; byte xi;
        for (i = 0; i < n; i++) s += p[i];
        {
            byte[] x = new byte[s];
            for (k = i = 0; i < n; i++)
                for (xi = w[i], j = p[i]; j > 0; j--) x[k++] = xi;
            w = x;
        }
        {
            byte[] x = new byte[s];
            for (k = i = 0; i < n; i++)
                for (xi = v[i], j = p[i]; j > 0; j--) x[k++] = xi;
            v = x;
        }
        string[] pItems = new string[s]; string itemI;
        for (k = i = 0; i < n; i++)
            for (itemI = items[i], j = p[i]; j > 0; j--) pItems[k++] = itemI;
        items = pItems;
    }
}