0-1背包 (附解析样例)--动态规划

问题描述:

给定n个物品和一个背包。物品i的重量为wi,价值为vi,背包容量为c

如何选择装入背包中的物品,使得装入背包的物品的价值最大?

从第n个物品开始依次向前装,装的顺序为:(n, n-1, n-2, , i+1, i, i-1, , 1

函数、数组等声明:

 n 共有n个物品

c 背包总重量为c

v[i] 物品i价值为vi

w[i]物品i的重量为wi

x[i]   x[i]=0,第i件物品不装入背包,x[i]=1,第i件物品装入背包

m(i, j):背包容量为j,选择物品为n, n-1, n-2, , i+1, i 装入背包产生的价值

Knapsack(int v[],int w[],int c,int n,int m[][10])   确定m(i, j)的值,得到最优解

Traceback(int m[][10],int w[],int c,int n,int x[]) 构造最优解(x1,x2,,xn)算法

问题分析:

用二维数组m[i][j], 0jc, 来存储m(i, j)的值。

求解0-1背包问题就是在二维数组m中填入相应的值。

m[1][c]中的值就是该背包问题的解

寻找递推关系的过程:

第一,包的容量比商品i体积小,装不下,此时的价值与前n-i个的价值是一样的,即m(i,j)=m(i+1,j)

第二,还有足够的容量可以装该商品,但装了也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即m(i,j)=maxm(i+1, j)m(i+1,j-wi)+vi

其中m(i+1,j)表示不装i的价值,m(i+1,j-wi)+vi 表示装了第i个商品,背包容量减少w(i), 但价值增加了v(i)

递推关系式如下:

二维数组m中最先填入物品n的最优解m(n, j)

然后依次按照递推式求出m(i,j).

Knapsack算法过程:

void Knapsack(int v[],int w[],int c,int n,int m[][10])
{
    //由n→1计算
    //i=n时
    int jMax=min(w[n]-1,c);//背包剩余容量上限
    for(int j=0;j<=jMax;j++)
    {
        m[n][j]=0;
    }
    for(int j=w[n];j<=c;j++)
    {
        m[n][j]=v[n];
    }
    //从第n-1个到第2个
    for(int i=n-1;i>1;i--)
    {
        jMax=min(w[i]-1,c);
        for(int j=0;j<=jMax;j++)
        {
            m[i][j]=m[i+1][j];
        }
        for(int j=w[i];j<=c;j++)
        {
            m[i][j]=max( m[i+1][j],m[i+1][j-w[i]]+v[i]  );
        }
    }
    //第1个
    if(c>=w[1])
    {
        m[1][c]=max( m[2][c],m[2][c-w[1]]+v[1] );
    }

}

 构造最优解(x1,x2,,xn)算法:

如果m[1][c]=m[2][c], x1=0, 否则x1=1;

如果x1=0, 则由m[2][c]构造解;

如果x1=1, 则由m[2][c-w1]构造解;

依次类推,可构造出相应的最优解:x1,x2,,xn

Traceback算法过程:

void Traceback(int m[][10],int w[],int c,int n,int x[])//构造最优解(x1,x2,…,xn)算法
{
    for(int i=1;i<n;i++)
    {
        if(m[i][c]==m[i+1][c])
        {
            x[i]=0;
        }
        else
        {
            x[i]=1;
            c-=w[i];
        }
    }
    x[n]=(m[n][c])?1:0;
}

完整代码实现:

#include<iostream>
using namespace std;
#define N 10
int n;//共有n个物品
int c;//背包总重量为c
int v[N];//物品i价值为vi
int w[N];//物品i的重量为wi
int m[N][N];//m(i,j):背包容量为j,可选择物品为i
int x[N];//x[i]=0,第i件物品不装入背包,x[i]=1,第i件物品装入背包
void Knapsack(int v[],int w[],int c,int n,int m[][10])
{
    //由n→1计算
    //i=n时
    int jMax=min(w[n]-1,c);//背包剩余容量上限
    for(int j=0;j<=jMax;j++)
    {
        m[n][j]=0;
    }
    for(int j=w[n];j<=c;j++)
    {
        m[n][j]=v[n];
    }
    //从第n-1个到第2个
    for(int i=n-1;i>1;i--)
    {
        jMax=min(w[i]-1,c);
        for(int j=0;j<=jMax;j++)
        {
            m[i][j]=m[i+1][j];
        }
        for(int j=w[i];j<=c;j++)
        {
            m[i][j]=max( m[i+1][j],m[i+1][j-w[i]]+v[i]  );
        }
    }
    //第1个
    if(c>=w[1])
    {
        m[1][c]=max( m[2][c],m[2][c-w[1]]+v[1] );
    }

}
//x[i]=0,第i件物品不装入背包,x[i]=1,第i件物品装入背包
void Traceback(int m[][10],int w[],int c,int n,int x[])//构造最优解(x1,x2,…,xn)算法
{
    for(int i=1;i<n;i++)
    {
        if(m[i][c]==m[i+1][c])
        {
            x[i]=0;
        }
        else
        {
            x[i]=1;
            c-=w[i];
        }
    }
    x[n]=(m[n][c])?1:0;
}
int main()
{

    cin>>n>>c;
    for(int i=1;i<=n;i++)
    {
        cin>>w[i]>>v[i];
    }
    for(int i=1;i<=n;i++)//初始化
        for(int j=0;j<=c;j++)
            m[i][j]=0;
    Knapsack( v, w, c, n, m);
    Traceback(m,w,c, n, x);
    for(int i=1;i<=n;i++)
    {
        if(i==1)
            cout<<x[i];
        else
            cout<<" " <<x[i];
    }
    cout<<endl;
    cout<<m[1][c];
    return 0;
}




  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值