算法导论16.2-2

来源:互联网 发布:淘宝丝袜买家秀 编辑:程序博客网 时间:2024/06/13 22:52
  1. 问题描述
    设计动态规划算法求解0-1背包问题,要求运行时间为O(nW)n为商品数,W是小偷能放进背包的最大商品总重量。0-1背包问题用公式表示为:
    maximizei=1nvixisubjecttoi=1nwixiWxi{0,1}

    其中vi是商品的价值,wi是商品的重量,W是背包的容量。
  2. 一个递归解
    假设V[i,j]:总重量不超过j的前提下,前i种商品总价值的最大值。显然,当ij有一个为0,那么V[i,j]=0。当i0j0时,V[i,j]的求解可以由它的子问题给出:①若jw[i],则求解V[i,j]时可以选第i件商品对应的最大价值为v[i]+V[i1,jw[i]](此时的最大值取决于在总重量不超过jw[i]的前提下,前i1种商品总价值的最大值。);也可以不选择第i件商品,对应的最大价值为V[i1,j](此时的最大值即是在总重量不超过j的前提下,前i1种商品总价值的最大值。)。②若j<w[i],不能选择第i件商品,此时所选商品的最大价值即在总重量不超过j的前提下,前i1种商品总价值的最大值V[i1,j]。综上可得如下递归式:
    V[i,j]=0max{V[i1,j],v[i]+V[i1,jw[i]]}jw[i]V[i1,j]j<w[i]
  3. 求解商品的最大价值
    为了跟踪所选的商品,用B[i,j]表示在j的限制下从前i件商品中构造的最优解是否含有商品i
    设计算法的伪代码如下:
    KNAPSACK-BST(v,w)
for i=0 to n    V[i,0]=0for j=1 to W    V[0,j]=0for i=1 to n    for j=1 to W        if j-w[i]>=0            if V[i-1,j]>(v[i]+V[i-1,j-w[i]])                V[i,j]=V[i-1,j]            else                V[i,j]=v[i]+V[i-1,j-w[i]]                B[i,j]=1        else            V[i,j]=V[i-1,j]return V[n,W]
  1. 构造最优解
    PRINT-KNAPSACK(i,j)
if i=0 or j=0    returnif B[i,j]==1    print "Item" i    PRINT-KNAPSACK(i-1,j-w[i])else    PRINT-KNAPSACK(i-1,j)
  1. C++实现
#include<iostream>#include<string>#include<algorithm>#define NUM 50#define INT 65536using namespace std;int W;int v[NUM];int w[NUM];int V[NUM][NUM];int B[NUM][NUM];int KNAPSACK_BST(int n){    for (int i = 0; i <= n; i++)        V[i][0] = 0;    for (int j = 1; j <= W; j++)        V[0][j] = 0;    for (int i = 1; i <= n; i++){        for (int j = 1; j <= W; j++){            if (j - w[i] >= 0){                if (V[i - 1][j] > (v[i] + V[i - 1][j - w[i]]))                    V[i][j] = V[i - 1][j];                else{                    V[i][j] = v[i] + V[i - 1][j - w[i]];                    B[i][j] = 1;                }            }            else                V[i][j] = V[i - 1][j];        }    }    return V[n][W];}void PRINT_KNAPSACK(int i, int j){    if (i == 0 || j == 0)        return;    if (B[i][j] == 1){        cout << "Item" << i << " ";        PRINT_KNAPSACK(i - 1, j - w[i]);    }    else        PRINT_KNAPSACK(i - 1, j);}void main(){    int n;    cin >> n;    for (int i = 1; i <= n; i++)        cin >> v[i];    for (int j = 1; j <= n; j++)        cin >> w[j];    cin >> W;    cout << KNAPSACK_BST(n) << endl;    PRINT_KNAPSACK(n, W);    cout << endl;}

输入样例

i123v60100120w102030

W=3
输出结果
这里写图片描述