【问题标题】:wrong output for memoization solution of knapsack issue背包问题的记忆解决方案的错误输出
【发布时间】:2015-05-10 10:51:30
【问题描述】:

我需要递归、记忆和动态规划来解决背包问题。目前我停留在记忆方法(部分是动态编程方法)。

我根据在互联网上其他地方找到的代码改编了代码。目前输出不正确。

问题涉及利润和质量。每个项目都有关联的利润和质量,有 MAX_N(数量)个可用项目和 MAX_CAPACITY 用于质量。目的是在背包中获得尽可能多的“利润”。

以下是练习提供的示例:

示例:给定一个容量为 5 的背包,物品的质量 [] = {2, 4, 3, 2} 和​​利润利润 [] = {45, 40, 25, 15},最好的组合是物品0(质量为 2,利润为 45)和项目 2(质量为 3,利润为 25),总利润为 70。质量为 5 或更少的其他组合没有更大的利润。

完整代码如下:

#include <stdio.h>

#define MAX_N 10
#define MAX_CAPACITY 165

int m[MAX_N+1][MAX_CAPACITY+1];

int max(int x, int y) {
    return x ^ ((x ^ y) & -(x < y));
}

int min(int x, int y) {
    return y ^ ((x ^ y) & -(x < y));
}

int knapsackRecursive(int capacity, int mass[], int profit[], int n) {

    if (n < 0)
        return 0;

    if (mass[n] > capacity)
        return knapsackRecursive(capacity, mass, profit, n-1);

    else
        return max(knapsackRecursive(capacity, mass, profit, n-1), knapsackRecursive(capacity - mass[n], mass, profit, n-1) + profit[n]);

}

int knapsackMemoized(int capacity, int mass[], int profit[], int n) {

    int take = 0;
    int dontTake = 0;

    if (m[n][capacity] != 0)
        return m[n][capacity];

    if (n == 0) {

        if (mass[0] <= capacity) {
            m[n][capacity] = profit[0];
            return profit[0];
        }

        else {
            m[n][capacity] = 0;
            return 0;
        }
    }

    if (mass[n] <= capacity)
        take = profit[n] + knapsackMemoized(capacity-mass[n], mass, profit, n-1);

    dontTake = knapsackMemoized(capacity, mass, profit, n-1);

    m[n][capacity] = max(take, dontTake);

    return m[n][capacity];

}

int knapsackDynamic(int capacity, int mass[], int profit[], int n) {

    // this only works with int m[MAX_N+1][MAX_CAPACITY+1];

    int i;
    int j;

    for (i = 0; i <= n; i++) {

        for (j = 0; j <= capacity; j++) {

            if (i == 0 || j == 0)
                m[i][j] = 0;

            else if (mass[i-1] <= j)
                m[i][j] = max(profit[i-1] + m[i-1][j-mass[i-1]], m[i-1][j]);

            else
                m[i][j] = m[i-1][j];
        }
    }

    return m[n][capacity];

}

void test() {

    // test values
    //int M1[MAX_N] = {2, 4, 3, 2};
    //int P1[MAX_N] = {45, 40, 25, 10};

    int M1[MAX_N] = {6, 3, 2, 4};
    int P1[MAX_N] = {50, 60, 40, 20};

    int M2[MAX_N] = {23, 31, 29, 44, 53, 38, 63, 85, 89, 82};
    int P2[MAX_N] = {92, 57, 49, 68, 60, 43, 67, 84, 87, 72};

    // a)
    printf("Recursion: %d\n",knapsackRecursive(MAX_CAPACITY, M1, P1, MAX_N));
    printf("Recursion: %d\n",knapsackRecursive(MAX_CAPACITY, M2, P2, MAX_N));
    printf("\n");

    // b)
    printf("Memoization: %d\n",knapsackMemoized(MAX_CAPACITY, M1, P1, MAX_N));
    printf("Memoization: %d\n",knapsackMemoized(MAX_CAPACITY, M2, P2, MAX_N));
    printf("\n");

    // c)
    printf("Dynamic Programming: %d\n",knapsackDynamic(MAX_CAPACITY, M1, P1, MAX_N));
    printf("Dynamic Programming: %d\n",knapsackDynamic(MAX_CAPACITY, M2, P2, MAX_N));

}

int main() {
    test();
}

这是输出:

Recursion: 170
Recursion: 309

Memoization: 170
Memoization: 170

Dynamic Programming: 170
Dynamic Programming: 309

Process returned 25 (0x19)   execution time : 0.014 s
Press any key to continue.

如您所见,递归和动态编程解决方案提供了正确的输出。 (我通过函数运行给定的示例数组进行了检查。)记忆方法目前没有。事实上,它总是为两个数组提供相同的结果,老实说,我真的很困惑。

另一个问题(虽然远没有那么大)是动态编程方法只适用于int m[MAX_N+1][MAX_CAPACITY+1];,但练习需要int m[MAX_N][MAX_CAPACITY];。我不确定如何更改代码以支持后者。

【问题讨论】:

  • 我不认为这是一个寻求家庭作业帮助的地方。
  • 这是一道编程题。我看不出有人进行编程的原因有什么相关性。
  • 实际上,这种反应是不必要的,我很抱歉。我查了一下,这似乎是关于作业问题的常见问题解答主题:meta.stackexchange.com/questions/10811/…

标签: c dynamic-programming memoization knapsack-problem


【解决方案1】:

所以我知道这是一道作业题,所以我不会给出正确答案,但我可以这样说:

如果函数在第二次运行时返回相同的答案,这通常是因为某些内容尚未归零。上一次运行留下了一些污垢。

检查您认为在函数范围之外创建的变量应该是干净的所有位置。

编辑:对于第二个问题,m[ITEM][CAP] 是一个矩阵,反映了每个项目剩余的每个上限的利润。这些项目是一个循环,在所有项目上运行一次。 1 to MAX0 to (MAX-1),这是一个具有最大单元数的数组。每个项目的上限可以是0 to MAX_CAP 包括在内的所有内容。该范围是 MAX_CAP+1 长,这意味着您需要创建 int m[MAX_N][MAX_CAPACITY+1]。我认为不可能以其他方式做到这一点,并且您的代码应该已经适用于此。

【讨论】:

  • 我实际上并没有考虑到这一点。是的,这很可能是问题,就像我注释掉第一个 memoization-printf 它显示第二组数组的正确结果一样。将进一步研究,谢谢!
  • 这绝对是记忆问题的问题。删除if (m[n][capacity] != 0) 后,它现在可以工作了。我想我对那里的安全有点过分热心,并在脚上开枪了。你能告诉我关于我发布的第二个问题的任何信息,关于动态编程部分需要 +1 的问题吗?
  • 很高兴你找到了那个。我将编辑答案以反映您的第二部分。
  • 哦,如果你不允许在函数范围之外分配一个那么大的矩阵,那么不要在动态编程函数中这样做。您可以在函数中创建它,并使其尽可能大。
  • 是的,我试了一会儿,发现如果我用for (j = 0; j &lt;= capacity; j++) {j = 1 做这行,就可以了。我现在得到正确的结果!感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-23
  • 2020-08-09
相关资源
最近更新 更多