0-1背包问题(0-1 Knapstack Problem)

1. 问题描述

设有 n 件物品,其中第 i 件的重量和价值分别为 w[ i ] 和 v[ i ], i = 1, ..., n。现在有一个容量为 V 的背包,要求选择其中的若干件装入背包,使得物品的总重量不超过背包的容量,并且总的价值最大。由于每件物品要么被选要么被不选,因此称为 0-1 背包问题。设 w[ i ],v[ i ],V 均为整数。

 

2. 动态规划解

用 opt[ i, j ] 表示用容量为 j 的背包装前 i 件物品的最大价值。则

  • opt[ i, 0 ] = 0, i = 0, 1, ..., n  //没有容量了
  • opt[ 0, j ] = 0    //没有东西可装
  • 对于i > 0,  j > 0
    • 如果 j >= w[ i ], 则 opt[ i, j ] = max{ v[ i ] + opt[ i - 1, j - w[ i ] ], opt[ i - 1, j ]
    • 如果 j < w[ i ], 则 opt[ i, j ] = opt[ i - 1, j ]

 

#include<iostream>
#include<vector>
#include<iterator>
#include<tuple>


template<class Iter1, class Iter2>
std::pair<size_t, std::vector<size_t>>
knapsack(Iter1 beg_w, Iter1 end_w, Iter2 beg_v, size_t V)
{
    const int n = end_w - beg_w;
    std::vector<std::vector<size_t>> opt(n + 1, std::vector<size_t>(V + 1));

    for(int i = 0; i <= n; ++i)
        opt[i][0] = 0;
    for(int j = 0; j <= V; ++j)
        opt[0][j] = 0;
    for(int i = 1; i <= n; ++i, ++beg_w, ++beg_v)
        for(int j = 1; j <= V; ++j)
        {
            if(*beg_w <= j)
            {
                auto tmp = opt[i - 1][j - *beg_w] + *beg_v;
                opt[i][j] = (tmp > opt[i - 1][j]) ? tmp : opt[i - 1][j];
            }
            else
                opt[i][j] = opt[i - 1][j];
        }

    //traceback
    std::vector<size_t> ans(n, 0);
    --beg_w;
    auto volume = V;
    for(int i = n; i > 0; --i)
    {
        if(opt[i][volume] > opt[i - 1][volume])
        {
            ans[i - 1] = 1;
            volume -= *beg_w;
        }
        --beg_w;
    }

    return std::make_pair(opt.back().back(), ans);
            

}

int main()
{
    std::vector<size_t> w = {5, 8, 5, 10};
    std::vector<size_t> v = {10, 16, 7, 10};
    std::vector<size_t> ans;
    size_t opt;
    std::tie(opt, ans) = knapsack(w.begin(), w.end(), v.begin(), 10);
    std::cout << opt << std::endl;
    for(auto x : ans)
        std::cout << x << ",";
    std::cout << std::endl;
}

 

 

 

 

 

 

 

 

posted @ 2013-09-22 21:53  半亩梨花  阅读(234)  评论(0编辑  收藏  举报