0-1背包问题
来源:互联网 发布:联合国统计数据库 编辑:程序博客网 时间:2024/05/22 15:15
问题描述: 给了n种物品和一个背包。物品的重量的W[i](weight),价V[i](value),背包容量为c(capacity),问应该如何选择放入背包中的物品,使得装入背包的物品总价值最大。
∑x[i]*w[i]<=c 1→n 且,价值∑x[i]*v[i]最大
设(y1,y2,y3,……Yn)是所给的0-1背包问题的一个最优解。 那么(y2,y3,……Yn)必须是
∑y[i]*w[i]<=c - w[1]y1 2→n 且,价值∑y[i]*v[i]最大
如果w[1]=0相当于没装,就是转换成2→n的物品放到容量c背包中,如果等于1,则该子问题就变成了去掉第 一个物品重量的背包问题
如果(y2,y3,……Yn)不是上述子问题的一个最优解,那么假设最优解为 (z2,z3,……Zn) 那么 ∑z[i]*v[i]才是该子问题的求出来的最大价值, 那么原问题,最优解,就变成了: x[1]*v[1] + ∑z[i]*v[i]2→n
那么得到的这个价值肯定比原先假设的最优解的价值还要大,很明显,这是与假设有矛盾的。 so, (y2,y3,……Yn)必须是0-1背包子问题的一个最优解!!
m[i][j] 代表 i→n物品,背包容量为j,0-1背包问题的最优解 w[i]重量 v[i]价值c背包容量
不放第i个物品:转成 ,i+1→物品放入容量为j的背包中的最大价值 放第i个物品:转成, i+1→物品放入容量为j-w[i]的背包中的最大价值+v[i].
j<w[i] 背包剩余的容量已经放不下了 则:m[i][j]= m[i+1][j]
m[n][j] = v[n] 能放下 j>=w[n] 0 放不下了 0<j<w[n] 然后就是具体的实现过程
最后得到的m[1][c]就是所要求的最优值。
每个物品只有两种可能的选择,放或者不放,所以称为0-1背包问题,
即要找到一个数组(x1,x2,……,Xn),x[i]∈{0,1},不放就是0,放入就是1
要求就是,
先看0-1背包问题是否满足最优子结构性质:
最优子结构的证明基本都是使用反证法来证明。
然后,就是递归关系了
一.j>=w[i]剩下的背包容量可以放下
二.只有第n个物品的时候
举个具体例子:
n=5,c=10,w={2,2,6,5,4},v={6,3,5,4,6}。
代码:
C++语言:
#include<iostream>
usingnamespacestd;
intMAX(int a , int b)
{
returna>b?a:b;
}
template<classType>
voidKnapsack(Type *v,int *w,int c,int n,int **m);
template<classType>
voidTraceback(Type **m ,int *w,int *x,intn,int c);
intmain()
{
int n; //物品个数
int c; //背包容量
int i,j;
cout<<"请输入物品个数:";
cin>>n;
cout<<"请输入背包容量:";
cin>>c;
int *w = new int[n+1]; //每个物品的重量。w[0]什么都不存,从1到n计算
int *v = new int[n+1]; //价值
int *x = new int[n+1]; //用于存放入或者不放的数组
cout<<"请输入每个物品的重量和价值:(中间用空格隔开)"<<endl;
for(i=1;i<n+1;i++)
cin>>w[i]>>v[i];
int **m = new int *[n+1]; //动态建立二维数组分配空间
for(i=0;i<n+1;i++)
m[i] = new int [c+1];
Knapsack(v,w,c,n,m);
Traceback(m,w,x,n,c);
cout<<"能装的最大价值是:"<<m[1][c]<<endl;
cout<<"可以装入的物品编号,物品重量和对应的价值是:"<<endl;
for(i=1;i<n+1;i++)
if(x[i]==1)cout<<"第"<<i<<"个物品:"<<w[i]<<" " <<v[i]<<endl;
return0;
}
//cout<<"hello,bug!"<<endl;
template<classType>
voidKnapsack(Type *v,int *w,int c,int n,int **m)
{
int i,j;
int jMax = MAX(w[n]-1,c);
if(jMax>c)jMax = c;
for(j=0;j<=jMax;j++)m[n][j] = 0;
for(j=w[n];j<=c;j++)m[n][j] = v[n];
//上面是对于m[n][j]的处理
for(i=n-1;i>1;i--)
{
jMax= MAX(w[i]-1,c);
if(jMax>c)jMax=c;
for(j = 0;j<=jMax;j++) m[i][j] = m[i+1][j]; //不能选择i的情况
for(j=w[i];j<=c;j++)m[i][j] = MAX(m[i+1][j],m[i+1][j-w[i]]+v[i]);
//m[i+1][j]代表能放入第i个数,但是不放入。
//m[i+1][j-w[i]]+v[i]代表放入了第i个数,至于前面能放入的数就看m[i+1][j-w[i]]的值了
m[1][c] = m[2][c];
if(c>=w[1])m[1][c] = MAX(m[2][c],m[2][c-w[1]]+v[1]); //因为第1这一行是属于没用到的子问题,所以就分开处理
}
}
template<classType>
voidTraceback(Type **m ,int *w,int *x,intn,int c)
{
int i;
for(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; //如果m[n][c]为0的话,显然没放,不然就放了
}
usingnamespacestd;
intMAX(int a , int b)
{
}
template<classType>
voidKnapsack(Type *v,int *w,int c,int n,int **m);
template<classType>
voidTraceback(Type **m ,int *w,int *x,intn,int c);
intmain()
{
}
//cout<<"hello,bug!"<<endl;
template<classType>
voidKnapsack(Type *v,int *w,int c,int n,int **m)
{
}
template<classType>
voidTraceback(Type **m ,int *w,int *x,intn,int c)
{
}
- 背包问题(0-1背包、完全背包、多重背包)详解
- 背包问题和0-1背包问题
- 背包问题和0-1背包问题
- 背包问题系列--"0-1背包问题"
- 背包笔记-含0/1背包问题、完全背包问题、多重背包问题、二维背包问题、分组背包问题
- 【背包问题】背包问题之0-1背包、完全背包、多重背包
- 0-1背包问题
- 0/1背包问题
- 0,1背包问题
- 0-1背包问题
- 0/1背包问题
- 0-1背包问题
- // 0-1背包问题
- 0/1背包问题
- 0-1背包问题
- 0-1背包问题
- 0-1背包问题
- 0/1背包问题
- 用g++编写一个hello,world
- O(n)时间求最接近中位数的k个数
- 后台coder的神器!Bootstrap && Layoutit
- DP之最基本的求最长公共子序列
- DP之简单的求最大字段和问题
- 0-1背包问题
- 简单DP之最少硬币问题(多重背包问…
- DP之一般背包问题
- 简单DP之二维背包问题
- 测试时间的一个模板
- STL的神器,优先队列
- [转]Uboot的Makefile
- #分支限界法#最小机器重量设计问题(优先队列)
- Objective-C GCD使用