算法设计--0-1背包问题通过动态规划
给定一个物品集合s={1,2,3,…,n},物品i的重量是wi,其价值是vi,背包的容量为W,即最大载重量不超过W。在限定的总重量W内,我们如何选择物品,才能使得物品的总价值最大。
如果物品不能被分割,即物品i要么整个地选取,要么不选取;
不能将物品i装入背包多次,也不能只装入部分物品i,则该问题称为0—1背包问题。
如果物品可以拆分,则问题称为背包问题,适合使用贪心算法。
假设xi表示物品i装入背包的情况,xi=0,1。
当xi=0时,表示物品没有装入背包; 当xi=1时,表示把物品装入背包。
因此问题就归结为找到一个满足上述约束方程, 并使目标函数达到最大的解向量。
p(i,j):背包容量j。 p(i+1,j):不装入物体i,背包容量j。 p(i+1,j-wi)+vi:装入物体i,背包容量j-wi。
#include<bits/stdc++.h>
using namespace std;
#define NUM 50//物品数量的上限
#define CAP 1500//背包容量的上限
int w[NUM];//物品的重量
int v[NUM];//物品的价值
int p[NUM][CAP];//用于递归的数组
void knapsack(int c,int n)//c是背包的容量,n是物品的数量
{//计算推理边界
int jMax=min(w[n]-1,c);//分界点
for( int j=0; j<=jMax; j++) p[n][j]=0;
for(int j=w[n];j<=c;j++)p[n][j]=v[n];
for(int i=n-1;i>1;i--)//计算递推式
{
jMax=min(w[i]-1,c);
for(int j=0;j<=jMax;j++)
p[i][j]=p[i+1][j];
for(int j=w[i];j<=c;j++)
p[i][j]=max(p[i+1][j],p[i+1][j-w[i]]+v[i]);
}
p[1][c]=p[2][c];//计算最优值
if(c>=w[1])p[1][c]=max(p[1][c],p[2][c-w[1]]+v[1]);
}
void traceback(int c,int n,int x[])
{
for(int i=0;i<n;i++)
{
if(p[i][c]==p[i+1][c])x[i]=0;
else{
x[i]=1;c-=w[i];
}
}
x[n]=(p[n][c])?1:0;
for(int i=0;i<n;i++)
{
cout<<x[i];//逆向推导
}
}
int main()
{
for(int i=0;i<4;i++)
{
cin>>w[i];//2 1 3 2 12 10 20 15
}
for(int i=0;i<4;i++)
{
cin>>v[i];
}
int x[4];
knapsack(5,4);
traceback(5,4,x);
}