用动态规划的思想解决0-1背包问题,编程实现:
有n种物品,每种物品仅有一件,第i件物品的重量为wi,价值为vi,现有一个承重量为c的背包。在不超过背包承重的情况下,应如何选择装入背包的物品,使得装入背包中物品的价值总和最大?
样例:n=5,c=8,w={2,2,7,5,4},v={3,6,4,5,6},求背包所装物品的最大价值是多少?最优解是什么?
动态规划的原理:
动态规划与分治法类似,都是把大问题拆分成小问题,通过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果。
Vi表示第 i 个物品的价值,Wi表示第 i 个物品的体积,定义V(i,j):当前背包容量 j,前 i 个物品最佳组合对应的价值,同时背包问题抽象化(X1,X2,…,Xn,其中 Xi 取0或1,表示第 i 个物品选或不选)。
1、建立模型,即求max(V1X1+V2X2+…+VnXn);
2、寻找约束条件,W1X1+W2X2+…+WnXn<capacity;
3、寻找递推关系式,面对当前商品有两种可能性:
包的容量比该商品体积小,装不下,此时的价值与前i-1个的价值是一样的,即V(i,j)=V(i-1,j);
还有足够的容量可以装该商品,但装了也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}。
其中V(i-1,j)表示不装,V(i-1,j-w(i))+v(i) 表示装了第i个商品,背包容量减少w(i),但价值增加了v(i);
由此可以得出递推关系式:
j<w(i) V(i,j)=V(i-1,j)
j>=w(i) V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}
最优解回溯:
V(i,j)=V(i-1,j)时,说明没有选择第i 个商品,则回到V(i-1,j);
V(i,j)=V(i-1,j-w(i))+v(i)时,说明装了第i个商品,该商品是最优解组成的一部分,随后我们得回到装该商品之前,即回到V(i-1,j-w(i));
一直遍历到i=0结束为止,所有解的组成都会找到。
#include<iostream>
#include <algorithm>
using namespace std;
int i,j;
int dp[30][100];
int item[100];
int value[100];
int weight[100];
int GetArray(int a[],int count)
{
for(int i=1;i<=count;i++)
cin>>a[i];
}
int GetMaxValue(int n,int m)
{
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(j<weight[i])
dp[i][j] = dp[i-1][j];
else
dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
}
}
}
int main()
{
int n,m;
cin>>n>>m;
GetArray(value,n);
GetArray(weight,n);
GetMaxValue(n,m);
cout<<"装入背包中物品总价值最大为:"<<endl;
cout<<dp[n][m]<<endl;
int b = m;
for(int i = n; i >= 1; i--){
if(dp[i][b] > dp[i - 1][b]){
item[i] = 1;
b -= weight[i];
}
}
cout<<"装入的物品的序号为:"<<endl;
for(int i = 1; i <= n; i++)
//cout << item[i] << " ";
if(item[i]==1)
cout<<i<<" ";
cout<<endl;
return 0;
}
运行结果: