利用动态规划求解01背包问题

问题描述

现在我们有n件物品,每件物品有其对应的重量(w)和对应的价值(v),现在有一个背包可以用来装这些物品,但是由于其承重量有限,故有一个最大承重c。
现在给定物品的件数,背包的承重,以及每一件物品对应的重量和质量,我们求出在这种情况下,背包装的物品的最大价值。

如下:

输入:
5 17 (5件商品 背包最大承重为 17)
3 6 (5件商品对应的重量以及价值)
1 4
8 13
6 10
16 24
输出:
29

问题解析

假设我们有m件物品,我们将其表示为向量形式:

N={n1,n2,,ni,,nm}

对于第 i 将物品我们对它有两种处理方式:加入背包,不加入背包

加入我们用1表示将其加入,用0表示不将其加入。

故原来的问题就变成求一向量:

X={x1,x2,,xi,,xn} xi={0,1}, 1in

结构分析

不难证明该问题具有最优子结构和重复子问题,故可以用动态规划进行求解!

我们来分析一下该问题的递推公式:
我们用 i 表示第 i 件物品,用 j 表示该背包当前可装的物品的总重量。
m[i][j] 表示在背包只能装前 i 件物品,且当前只能装总重量为 j 的情况下的背包能装的物品的最大价值。
w[i],v[i] 分别表示第 i 件物品的重量和价值。

  i==0    j==0  

m[i][j]=0

  w[i]j  

m[i][j]=max{v[i]+m[i1][jw[i]],m[i1][j]}

  w[i]>j  

m[i][j]=m[i1][j]

我们以上面题目描述中的例子自底向上画出如下二维表:

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
0 4 4 6 10 10 10 10 10 10 10 10 10 10 10 10 10 10
0 4 4 6 10 10 10 10 13 17 17 19 23 23 23 23 23 23
0 4 4 6 10 10 10 14 14 17 20 20 23 23 23 27 27 29
0 4 4 6 10 10 10 14 14 17 20 20 23 23 23 27 27 29

我们对该表进行回溯处理即可的到相应的解向量:

    //回溯求解 解向量
    int i=n;
    int j=c;

    while(i>0&&j>0){
        if(m[i][j]!=m[i-1][j]){
            x[i]=1;
            j-=w[i];
        }
        cout<<"j="<while(m[i][j]==m[i][j-1]) j--;
    }

程序代码

#include

#define MAX_LEN 100

using namespace std;

int n;                  //记录物品的数量 

int w[MAX_LEN]={0};         //记录第 i 个物品的重量
int v[MAX_LEN]={0};         //记录第 i 个物品的价值 

int c;                  //记录背包的总容量 

int m[MAX_LEN][MAX_LEN];    // m[i][j] 记录在有前 i 个物品 背包容量为 j 的时候的最大价值  

int x[MAX_LEN]={0};         //保存解向量  1:加入 0:不加入 
/**
 * @author zjq~
 * @time 2017/07/09
 * @func 动态规划求解 01背包问题 
 */ 

void getMaxValue(){

    for(int i=0;i<=n;i++){          //当前拥有前 i 个物品 
        for(int j=0;j<=c;j++){      //记录背包容量 
            if(i==0||j==0){
                m[i][j]=0;
            }
            else if(w[i]<=j){       //当前物品的重量小于背包容量 比较加入后吧不加的值 
                m[i][j]=(v[i]+m[i-1][j-w[i]])>m[i-1][j]?(v[i]+m[i-1][j-w[i]]):m[i-1][j]; 
            }
            else{                   //当前物品的质量大于背包的容量 不加入 
                m[i][j]=m[i-1][j]; 
            }
            cout<" ";
        }
        cout<//回溯求解 解向量
    int i=n;
    int j=c;

    while(i>0&&j>0){
        if(m[i][j]!=m[i-1][j]){
            x[i]=1;
            j-=w[i];
        }
        cout<<"j="<while(m[i][j]==m[i][j-1]) j--;
    }
} 

int main(){

     cin>>n>>c;

     for(int i=1;i<=n;i++){
        cin>>w[i]>>v[i];
     } 

    getMaxValue();

    cout<<"背包能装下的最大价值为:"<cout<<"解向量如下:";
    for(int i=1;i<=n;i++){
        cout<" ";
    }
} 

输出示例:

5 17
3 6
1 4
8 13
6 10
16 24
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
0 4 4 6 10 10 10 10 10 10 10 10 10 10 10 10 10 10
0 4 4 6 10 10 10 10 13 17 17 19 23 23 23 23 23 23
0 4 4 6 10 10 10 14 14 17 20 20 23 23 23 27 27 29
0 4 4 6 10 10 10 14 14 17 20 20 23 23 23 27 27 29
j=17
j=11
j=3
j=3
j=0
背包能装下的最大价值为:29
解向量如下:1 0 1 1 0

最后

九度OJ题目链接:http://ac.jobdu.com/problem.php?pid=1123

你可能感兴趣的:([,算法,算法基础,])