没有重复的背包:最大数量的金币

Posted

技术标签:

【中文标题】没有重复的背包:最大数量的金币【英文标题】:Knapsack without repitions: Maximum Amount of Gold 【发布时间】:2019-12-22 14:01:43 【问题描述】:

来自 Coursera 的算法工具箱课程。

问题介绍

给你一组金条,你的目标是尽可能多地把金条放进去 你的包。每个栏只有一个副本,对于每个栏,您可以接受或不接受 (因此你不能拿一小节)。

问题描述

任务。给了????金条,找到装进一袋容量的最大黄金重量????。 输入格式。输入的第一行包含容量 ????一个背包和号码????金条。下一行包含 ????整数 ????0,????1, . . . ,??????????−1 定义金条的重量。

约束。 1≤???? ≤ 10^4; 1≤???? ≤ 300; 0 ≤ ??0, . . . , ????????−1 ≤ 10^5.

输出格式。输出能装进一个背包容量的最大黄金重量????。

我在 C++ 中的解决方案:

const int WEIGHT_MAX = 1000 + 1;
const int ITEMS_COUNT_MAX = 300 + 1;

int optimal_weight(int W, const vector<int> &w) 
  int weights[ITEMS_COUNT_MAX][WEIGHT_MAX];
  const int w_size = w.size();

  for (int i = 0; i <= w_size; i++) 
    for (int j = 0; j <= W; j++)       
        if (i==0 || j==0) 
          weights[i][j] = 0;
        else if (w[i - 1] <= j) 
          weights[i][j] = std::max(w[i - 1] + weights[i - 1][j - w[i - 1]],  weights[i - 1][j]);
        else
          weights[i][j] = weights[i - 1][j];
    
  

  int result = weights[w_size][W];
  return result;

对于输入

10 3
1 4 8

...它产生以下二维矩阵:

0 0 0 0 0 0 0 0 0 0 0
0 1 1 1 1 1 1 1 1 1 1
0 1 1 1 4 5 5 5 5 5 5
0 1 1 1 4 5 5 5 8 9 9

但是 14 年级学生的第 9 次考试没有通过。评分者不提供它使用的输入。

有人可以指出解决方案中可能存在的警告吗?

已更新 [感谢 Matt 解决]: 必须在堆上分配内存,因为本地堆栈大小不足以容纳大小为 10001х301 的数组。实际上,尝试在堆栈上分配时出现分段错误错误。

int optimal_weight(int W, const vector<int> &w) 
  const int w_size = w.size();
  int** weights = new int* [w_size + 1];

  for (int i = 0; i <= w_size; i++) 
    weights[i] = new int[W + 1];
  

  for (int i = 0; i <= w_size; i++) 
    for (int j = 0; j <= W; j++)       
        if (i==0 || j==0) 
          weights[i][j] = 0;
        
        else if (w[i - 1] <= j) 
          weights[i][j] = std::max(w[i - 1] + weights[i - 1][j - w[i - 1]],  weights[i - 1][j]);
        else
          weights[i][j] = weights[i - 1][j];
    
  

  int result = weights[w_size][W];

  for (int i = 0; i < w_size; i++) 
    delete[] weights[i];
  

  delete[] weights;

  return result;

【问题讨论】:

会不会是时间问题? 【参考方案1】:

计算很好,但最大权重为 10000,而您的矩阵仅上升到 1001,因此您遇到了缓冲区溢出。

首先在堆栈上分配矩阵并不好,当你解决这个问题时情况会更糟。

此外,您实际上并不需要二维矩阵来解决这个问题。

尝试维护可访问权重的排序列表。从 [0] 开始,为每个项目添加新的可访问权重。

【讨论】:

谢谢马特。是的,您对限制是正确的!我已经更新了问题。 那个算法总是给我正确的结果。我什至实现了一个生成随机数据的测试,结果总是正确的。我正在得出结论,问题出在分级机上。 您错过了有关缓冲区溢出的部分?试试 W=10000 是的,我完全搞砸了本地堆栈限制。再次感谢您,马特! 除了动态方法的帮助之外,我没有考虑任何其他方法来解决这个问题,因为它应该使用背包 0/1(无重复)算法来解决。感谢您让我知道还有另一种方法可以做到这一点。

以上是关于没有重复的背包:最大数量的金币的主要内容,如果未能解决你的问题,请参考以下文章

20191110luogu3698小Q的棋盘 | 树形背包dp | 贪心

有史以来最大数量的恐龙[重复]

最大字典键应具有相等数量的值[重复]

阿玛拉王国初始6千万背包6千万金币存档

无重复背包与有重复背包的不同应用

嵌套元组的最大值[重复]