algorithm - 0/1 背包动态规划优化,从2D矩阵到1D矩阵

标签 algorithm optimization dynamic-programming knapsack-problem

我需要维基百科的一些说明:Knapsack , 一边

This solution will therefore run in O(nW) time and O(nW) space. Additionally, if we use only a 1-dimensional array m[W] to store the current optimal values and pass over this array i+1 times, rewriting from m[W] to m[1] every time, we get the same result for only O(W) space.

我无法理解如何将二维矩阵转换为一维矩阵以节省空间。此外,rewriting from m[W] to m[1] every time 意味着什么(或者它是如何工作的)。

请提供一些例子。假设我有集合 {V,W} --> {(5,4),(6,5),(3,2)} 且 K = 9。

一维数组会是什么样子?

最佳答案

我知道这是一个老问题。但是我不得不花一些时间来搜索这个,我只是在这里记录这些方法以供任何人将来引用。

方法一
使用 N 行的直接 2D 方法是:

int dp[MAXN][MAXW];
int solve()
{
    memset(dp[0], 0, sizeof(dp[0]));
    for(int i = 1; i <= N; i++) {
        for(int j = 0; j <= W; j++) {
            dp[i][j] = (w[i] > j) ? dp[i-1][j] : max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]);
        }
    }
    return dp[N][W];
} 

这使用 O(NW) 空间。

方法二
您可能会注意到,在为特定行计算矩阵的条目时,我们只查看前一行而不是之前的行。这可以被利用来仅维护 2 行并继续交换它们作为当前行和上一行的角色。

int dp[2][MAXW];
int solve()
{
    memset(dp[0], 0, sizeof(dp[0]));
    for(int i = 1; i <= N; i++) {
        int *cur = dp[i&1], *prev = dp[!(i&1)];
        for(int j = 0; j <= W; j++) {
            cur[j] = (w[i] > j) ? prev[j] : max(prev[j], prev[j-w[i]] + v[i]);
        }
    }
    return dp[N&1][W];
}  

这需要 O(2W) = O(W) 空间。 cur 是第 i 行,prev 是第 (i-1) 行。
方法三
如果你再看一遍,你会发现当我们在一行中写一个条目时,我们只查看前一行左边的项目。我们可以使用它来使用单行并从右到左处理它,这样当我们计算一个条目的新值时,其左侧的条目具有它们的旧值。这是一维表法。

int dp[MAXW];
int solve()
{
    memset(dp, 0, sizeof(dp));
    for(int i =1; i <= N; i++) {
        for(int j = W; j >= 0; j--) {
            dp[j] = (w[i] > j) ? dp[j]: max(dp[j], dp[j-w[i]] + v[i]);
        }
    }
    return dp[W];
}

这也使用了 O(W) 空间,但只使用了一行。必须反转内循环的主要原因是因为当我们使用dp[j-w[i]]时,我们需要外循环上一次迭代的值。为此,必须以从大到小的方式处理 j 值。

测试用例(来自http://www.spoj.com/problems/PARTY/)

N = 10, W = 50
w[] = {0, 12, 15, 16, 16, 10, 21, 18, 12, 17, 18} // 1 based indexing
v[] = {0, 3, 8, 9, 6, 2, 9, 4, 4, 8, 9}

答案 = 26

关于algorithm - 0/1 背包动态规划优化,从2D矩阵到1D矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17246670/

相关文章:

algorithm - 仅在平面一侧的两个轴对齐框之间的碰撞检测

c++ - 从 C++ 调用 matlab fmincon

algorithm - "Charge changing"算法

swift - SceneKit 的立方体测试性能

algorithm - 查找可被给定数字整除的数组元素的最大总和

c# - 将递归方法转换为非递归 C#

algorithm - 使用 n*log(n) 算法预处理树

algorithm - 二叉搜索树的最小高度插入顺序

sql - 设计数据库并编写用于评分应用的 SQL 查询

dynamic-programming - 使用动态规划查找总和最接近给定数字 M 的数字子集