【问题标题】:dynamic programming matrix fill for Knapsack背包的动态规划矩阵填充
【发布时间】:2013-11-01 20:12:07
【问题描述】:

如果我有以下限制:

values = {$1,$2,$3,$4}  
items = {blue,yellow,green,red}  
weights = {1,2,3,4}  
capacity = 4

我想用代表项目权重的列和代表所选项目数的行来填写我的矩阵:

       1      2     3    4    

1     $1     $1    $1    $1
      {1}    {1}   {1}   {1}    
2     $1     $1    $3      $3
      {1}    {1}  {1,2}   {1,2}  
3     $1     $1    $3      $3    
      {1}    {1}  {1,2}   {1,2}
4     $1     $1    $3      $3      <--- should be 4?
      {1}    {1}  {1,2}    {1,2}

我期望看到的是一个解决方案,它提供4 作为正确的美元金额,但我得到了3。大括号 {} 中的数字代表 one based 索引以查找其中的项目。我的矩阵填充哪里出错了?

【问题讨论】:

  • 右边/底部上方的单元格有问题,应该是 $4 {1,3}。但即使没有,右边/底部的单元格也应该显示 $4 {4},所以那里也出错了。
  • @harold 所以在位置 (3,3) 它应该说 {1,3} ?
  • 我的意思是位置 (3, 4),即您指向的单元格的正上方

标签: algorithm matrix language-agnostic dynamic-programming


【解决方案1】:

解决方案是这样的

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

// m[a][b] = NOWAY => There's no way to represent 
// weight `b` with first `a` items
const int NOWAY = -1;
typedef vector<vector<int>> vvi;

const int values[] = {1, 2, 3, 4}; 
const string items[] = {"blue", "yellow", "green", "red"}; 
const int weights[] = {1, 2, 3, 4};
const int capacity = 4;
const int itemcount = 4;

void rec(vvi const & m, int represent, int mx, vvi & sol);

int main() {
    // m[i][j] -- total value
    // i -- items 1..i were taken
    // j -- total weight of those items
    vvi m(itemcount + 1, vector<int>(capacity + 1, NOWAY));

    // No items weight nothing. The other values we're yet to build
    m[0][0] = 0;
    for (int i = 1; i <= itemcount; ++i) {
        m[i] = m[i - 1];
        int w = weights[i - 1];
        // Find new representations
        for (int j = capacity - w; j >= 0; --j) {
            if (m[i][j] != NOWAY) {
                m[i][j + w] = max(m[i][j + w], m[i][j] + values[i - 1]);
            }
        }
    }
    // Output table
    for (int i = 0; i <= itemcount; ++i) {
        for (int j = 0; j <= capacity; ++j)
            m[i][j] == NOWAY ? cout << "x " : cout << m[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
    // Find the index of the best solution (it's always in the last row)
    int mxi = 0;
    for (int i = 1; i <= capacity; ++i)
        if (m.back()[mxi] < m.back()[i])
            mxi = i;
    // Recurse to get all the representations
    vvi solutions;
    rec(m, mxi, itemcount, solutions);
    // Output them
    for (int i = 0, ilen = solutions.size(); i < ilen; ++i) {
        cout << '{';
        bool f = true;
        for (int j = 0, jlen = solutions[i].size(); j < jlen; ++j) {
            if (!f) cout << ", ";
            cout << items[solutions[i][j]];
            f = false;
        }
        cout << "}" << endl;
    }
}

vector<int> path;
void rec(vvi const & m, int represent, int mx, vvi & sol) {
    if (represent == 0) {
        sol.push_back(path);
        return;
    }
    if (mx <= 0) return;
    for (int i = mx - 1; i >= 0; --i) {
        if (represent < weights[i])
            continue;
        if (m.back()[represent - weights[i]] == m.back()[represent] - values[i]) {
            path.push_back(i);
            rec(m, represent - weights[i], i, sol);
            path.pop_back();
        }
    }
}

返回

0 x x x x
0 1 x x x
0 1 2 3 x
0 1 2 3 4
0 1 2 3 4

{red}
{blue, green}

(顺便说一下,可以考虑在USACO 或Topcoder 进行培训。)

【讨论】:

  • 第一行不应该全是 1(不是1 0 0 0)吗?每个单元格通常代表您可以对重量小于或等于当前重量的项目执行的最佳操作(否则您的最终检查必须遍历一些值以找到最佳值,而不仅仅是返回角落单元格)。
  • @Dukeling 你不能代表重量为 2 或更多只有一件重量为 1 的物品。
  • @polkovnikov.ph 我说“小于或等于”。我并不是说这是错误的,只是这不是通常的方式(而且速度稍慢)。那为什么第二行不是1 2 3 0,那么最后一个2表示的只是一个权重2的物品,而权重应该是4?
  • @Dukeling 是的,当然,有一个错误。谢谢。
猜你喜欢
  • 2014-01-05
  • 2013-06-19
  • 1970-01-01
  • 2017-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-09
  • 1970-01-01
相关资源
最近更新 更多