动态规划:0-1背包问题

来源:互联网 发布:西门子博图软件 编辑:程序博客网 时间:2024/06/08 16:44

0-1背包问题是比较经典的动态规划,题意如下:

给定n件物品的重量和对应价值,给定一个背包的最大承重,求该背包所能装下的物品的最大价值,并输出哪几件装进了背包。

这个问题可以用一个二维数组来做,这样非常直观明了。但是有些情况下,数据过大,采用二维数组会超空间,所以需要采用一维数组进行空间压缩,复杂度是不变的,要注意的是填充一维数组时需要倒序。每次更新一遍一维数组,其实就相当于二维数组的更新。

下面是二维数组的方法,一维数组的方法在其后:

最关键的一个公式是
d[i][j] = max(d[i - 1][j], d[i - 1][j - w[i]] + v[i]);
其中,d[i][j]是指在前i件物品中,选择若干件放在承重为j的背包中,可以取得的最大价值。
先给出d[i][j]这个矩阵的示意图,因为我觉得在编程实现
过程中一直想着这个矩阵,思路会清晰很多。
这里写图片描述
这里,我统一把数组的第0个元素置为零,不使用(即:在上面的矩阵中,第0列全是0,不使用,就没有画出来。数组中的1就代表第一个)
代码如下,注释说的很清楚了:

#include <iostream>#include<algorithm>using namespace std;//d[i][j]是一个矩阵,表示在前i件物品中,选择若干件放在承重为j的背包中,可以取得的最大价值int main(){    int w[6] = {0, 2, 2, 6, 5, 4 }; //6件物品的重量    int v[6] = {0, 6, 3, 5, 4, 6 }; //6件物品的价值    int c = 10; //背包的最大承重量    int a[6] = { 0 }; //用来存储第i个物品是否装入背包    int d[6][11] = { 0 };  //矩阵    //接下来的双层for循环,用来填充矩阵    for (int j = 0; j <= 10; j++)        d[0][j] = 0;    for (int i = 1; i <= 5; i++){        for (int j = 0; j <= 10; j++) {            if (j < w[i]){      //如果背包装不了第i件,最大价值相当于和第i-1件的时候一样                d[i][j] = d[i - 1][j];              }            else{                d[i][j] = max(d[i - 1][j], d[i - 1][j - w[i]] + v[i]); //这个公式是核心!            }        }    }    //接下来的for循环,用来回溯,找到哪个物品放入了背包    int j = 10;    for (int i = 5; i > 0; i--){          //如果第i个和第i-1个不一样,说明第i个加进来了        if (d[i][j] > d[i - 1][j]){              a[i] = 1;            j = j - w[i];        }        else            a[i] = 0;    }    cout << d[5][10] << endl;    for (int i = 1; i <= 5; i++)        cout << a[i] << " ";    cout << endl;    return 0;}

填充一个一维数组的过程其实就是更新N遍,第i遍更新相当于上面的前i个物品容量不同时的最大价值。
下面是代码:

#include <iostream>#include <algorithm>#include <cstring>#include <stdio.h>using namespace std;int main(){    int w[6] = { 0, 2, 2, 6, 5, 4 }; //6件物品的重量    int v[6] = { 0, 6, 3, 5, 4, 6 }; //6件物品的价值    int c = 10; //背包的最大承重量    int dp[11] = { 0 };    for (int i = 0; i < 6; i++){        for (int j = c; j >= w[i]; j--){ //对这个数组倒序填充            dp[j] = max(dp[j], dp[j - w[i]] + v[i]);        }    }    cout << dp[c] << endl;    return 0;}
1 0
原创粉丝点击