动态规划法求背包问题

时间:2022-12-05 04:23:47

0-1背包问题是指给定一个容量一定的背包和一系列已知重量和价值的物品,从中选择一些物品放入背包使得背包中物品的总价值最大.

背包问题可以用动态规划,回溯法或者贪心算法求解.这里介绍使用动态规划法求解0-1背包问题.

动态规划法需要几个数组来辅助:

  • m: 背包最大容量

  • n: 物品的个数

  • w[i] : 第i个物品的重量

  • v[i]: 第i个物品的价值

  • c[i][j]: 前i个物品放入容量为j的背包最大的价值

动态规划法的最终目的是填写二维数组c,c[n][m]即为原问题的结果.

为了方便起见下标从1开始, i表示物品编号, j表示当前容量.先行后列,从上到下,从左到右填写二维数组c.

  • 若总容量小于物品质量(j < w[i]), 当前最大价值不变(c[i][j] = c[i-1][j])

  • 前i-1个物品选择装入第i个物品后正好装满的方案(c[i-1][j-w[i]]), 若装入后价值比前i-1个物品最大价值(c[i-1][j])更大,则装入第i个物品;

  • 否则保留前i-1个物品最大价值(c[i-1][j])

上述三种状态下

举一个简单的例子:

背包最大容量为10,有三个物品重量和价值分别为: (3,4),(4,5), (5,6),求背包最大价值.

填写二维数组c:

0 0 4 4 4 4 4 4  4  4 
0 0 4 5 5 5 9 9  9  9
0 0 4 5 6 6 9 10 11 11 

由此可知最大价值为11.

一言不发就丢代码:

 #include <stdio.h>

#define M 128
#define N 32

int m = 0, n = 0;
int c[N][M] = {0};
int w[N] = {0};
int v[N] = {0};

void npack() {
    int i, j;
    for (j=1; j <= m; j++) {
        for (i=1; i <= n; i++) {
            if (j < w[i]) {
                c[i][j] = c[i-1][j];
                continue;
            }
            else if(c[i-1][j-w[i]] + v[i] > c[i-1][j]) {
                c[i][j] = c[i-1][j-w[i]] + v[i];
            }
            else {
                c[i][j] = c[i-1][j];
            }
        }
    }
}

int main() {
    int i, j;
    // input
    scanf("%d %d", &m, &n);
    for (i = 1; i <= n; i++) {
        scanf("%d %d", &w[i], &v[i]);
    }
    npack();
    for (i = 1; i <= n; i++) {
        for (j = 1; j <= m; j++) {
            printf("%4d ", c[i][j]);
        }
        printf("\n");
    }
    return 0;
}