动态规划——0-1背包

来源:互联网 发布:伊藤网络超市 编辑:程序博客网 时间:2024/05/30 23:27

问题描述

  • 0-1背包问题可描述为:n个物品和1个背包。对物品i,其价值为vi,重量为wi,背包的容量为W。如何选取物品装入背包,使背包中所装入的物品的总价值最大?

  • 约束条件:
    约束条件

  • 目标函数:
    目标函数

  • 于是,问题归结为寻找一个满足约束条件(4-7),并使目标函数(4-8)达到最大的解向量X=(x1, x2,…, xn)。

最优子结构性质分析

  • 假设(x1, x2,…, xn)是所给0-1背包问题的一个最优解,则(x2,…, xn)是下面相应子问题的一个最优解:
  • 约束条件:
    约束条件
  • 目标函数:
    目标函数

建立最优值的递归关系

- 令C[i][j]= 目标函数

- C[0][j]=C[i][0]=0

递归关系式

算法设计——求装入背包的最大价值

  • 步骤1:设计算法所需的数据结构。采用数组w[n]来存放n个物品的重量;数组v[n]来存放n个物品的价值,背包容量为W,数组C[n+1][W+1]来存放每一次迭代的执行结果;数组x[n]用来存储所装入背包的物品状态;
  • 步骤2:初始化。按式(4-10)初始化数组C;
  • 步骤3:循环阶段。按式(4-11)确定前i个物品能够装入背包的情况下得到的最优值;
    – 步骤3-1:i=1时,求出C[1][j],1≤j≤W;
    – 步骤3-2:i=2时,求出C[2][j],1≤j≤W;
    – 依此类推,直到……
    – 步骤3-n:i=n时,求出C[n][W]。此时,C[n][W]便是最优值;

算法设计——确定装入背包的具体物品

  • 从C[n][W]的值向前推,如果C[n][W]> C[n-1][W],表明第n个物品被装入背包,则xn=1,前n-1个物品被装入容量为W-wn的背包中;否则,第n个物品没有被装入背包,则xn=0,前n-1个物品被装入容量为W的背包中。依此类推,直到确定第1个物品是否被装入背包中为止。由此,得到下面关系式:

  • 关系式

  • 按照上式,从C[n][W]的值向前倒推,即j初始为W,i初始为n,即可确定装入背包的具体物品。

构造实例

有5个物品,其重量分别为2,2,6,5,4,价值分别为6,3,5,4,6。背包容量为10,物品不可分割,求装入背包的物品和获得的最大价值。

算法描述

Int KnapSack(int n, int W, int w[ ],int v[ ]){    int I,j,c[n][W],x[n];   for(i=0;i<=n;i++)         c[i][0]=0;   for(i=0;i<=W;i++)         c[0][i]=0;   for(i=1;i<=n;i++)        for(j=1;j<=W;j++)             if(j<w[i])                c[i][j]=c[i-1][j];             else                c[i][j]=max(c[i-1][j],c[i-1][j-w[i]]+v[i]);//构造最优解    j=W;    for(i=n;i>0;i--)        if(c[i][j]>c[i-1][j])          {  x[i]=1;   j-=w[i];}        else             x[i]=0;     return c[n][w];}

代码实现

#include <iostream>using namespace std;int KnapSack(int W,int n,int *w,int *v,int **c);int main(){    int W,n,*w,*v,**c;//W背包总重量,n物品个数,*w 物品重量,*v物品价值 **c最优解    cout<<"请输入背包最大重量和物品个数: ";    cin>>W>>n;    w = new int[n+1];    v = new int[n+1];    cout<<"请输入各个物品重量和价值"<<endl;    for(int i=1;i<=n;i++){        cin>>w[i];    }    for(int i=1;i<=n;i++){        cin>>v[i];    }    c = new int*[n+1];    for(int i=0;i<=n;i++){        c[i] = new int[W+1];    }    KnapSack(W,n,w,v,c);    return 0;}int KnapSack(int W,int n,int *w,int *v,int **c){    int i,j,x[n];    for(i=0;i<=n;i++) c[i][0] = 0;    for(i=0;i<=W;i++) c[0][i] = 0;    for(i=1;i<=n;i++){        for(j=1;j<=W;j++){            if(j<w[i]){                c[i][j] = c[i-1][j];            }else if(c[i-1][j]>c[i-1][j-w[i]]+v[i]){                c[i][j] = c[i-1][j];            }else{                c[i][j] = c[i-1][j-w[i]]+v[i];            }        }    }    j = W;    for(i=n;i>0;i--){        if(c[i][j]>c[i-1][j]){            x[i] = 1;            j -= w[i];        }else{            x[i] = 0;        }    }    cout<<"最优解为";    for(i=1;i<=n;i++){        cout<<x[i]<<" ";    }    cout<<endl<<"矩阵为: "<<endl;;    for(i=0;i<=n;i++){        for(j=0;j<=W;j++){            cout<<c[i][j]<<" ";        }        cout<<endl;    }    return c[n][W];}

测试结果

测试结果

原创粉丝点击