问题描述:
给定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], 0≤j≤c, 来存储m(i, j)的值。
求解0-1背包问题就是在二维数组m中填入相应的值。
m[1][c]中的值就是该背包问题的解
寻找递推关系的过程:
第一,包的容量比商品i体积小,装不下,此时的价值与前n-i个的价值是一样的,即m(i,j)=m(i+1,j);
第二,还有足够的容量可以装该商品,但装了也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即m(i,j)=max{ m(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;
}