动态规划之0-1背包问题

问题描述:给定n种物品,1个背包,背包容量为c,每个物品i的价值为vi,重量为wi,如何选择装入物品能使背包的总价值最大?

注意:1)对于每个物品来说,只有两种选择,要么装,要么不装!

           2)不能将物品i装入背包多次,也不能只装入部分物品!

eg.c = 100 3种物品

1:v1 = 50  w1 = 30

2:v2 = 60  w2 = 20

3:v3 = 20  w3 = 70

 形式化描述:给定c >0, wi >0, vi >0 , 1≤i≤n.要求找一n元向量A=(x1,x2,…,xn), xi∈{0,1}(0表示“不装”,1表示“装”),1<=i<=n,使得 ∑ wixi≤c【物品的重量和小于背包总容量】而且∑ vixi达到最大。

递归关系:

对于物品有两个选择,要么装,要么不装,对于n个物品,则要做n种选择。现在设m[i][j]是背包容量为j,可选物品为i,i+1,...n【1<=i<=n】的0-1背包问题的最优解,找出递推公式:

<1>:如果放入第i件物品,那么m[i][j]=m[i+1][j-wi]+vi(可选物品变为i+1,i+2,....n,容量减去i的重量,价值加上i的价值

<2>:如果不放入第i件物品,那么m[i][j]=m[i+1][j](可选物品变为i+1,i+2,....n,容量不变,价值不变

设置循环关系时,采用自底向上的动态规划,先考虑当可选物品为最后一件物品(i=n,0<=j<=c)时,m[n][j]的取值(根据j的取值判断能否放下得出m[n][j]的取值),接下来i应该从n-1开始变化到1表示可选物品物品开始变成i,i+1,...n(同样根据j的取值判断能否放得下得到m[n][j]的取值)

要么放要么不放,所以取以上两种情况的最大值:m[i][j] = max(m[i+1][j-wi]+vi,m[i+1][j])

代码实现:

 

 1 #include <iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 int Knapsack(int n,int c,int w[],int v[],int m[][100]){
 5     int jMax = min(w[n]-1,c);//如果最小值是w[n]-1【最后一个物品重量减一】,说明以下j在0-jMax都放不下,如果最小值是c,那么也放不下,因为总容量比最后一个物品总容量减一还要小,肯定放不下 
 6     for(int j=0;j<=jMax;j++)m[n][j]=0;//容量为j【0<=j<=jMax,jMax为第n个物品的重量减一和背包容量c取最小值】,可选物品只有第n个物品的时候,背包肯定放不下,价值全部置0 
 7     for(int j=w[n];j<=c;j++)m[n][j]=v[n];//放的下,价值置为v[n],即第n个商品自己的价值 
 8     for(int i=n-1;i>1;i--){
 9         int jMax = min(w[i]-1,c);
10         for(int j=0;j<=jMax;j++)m[i][j]=m[i+1][j];//放不下,待选物品变为i+1,i+2,...n,价值不变
11         for(int j=w[i];j<=c;j++)m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);//放得下,取最大值 
12     }
13     m[1][c]=m[2][c];
14     if(c>=w[1])m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);
15     return m[1][c]; 
16 }
17 
18 int main(){
19     int n,c;//n件物品、背包容量为c, 
20     cin>>n>>c; 
21     int w[n],v[n]; 
22     for(int i=1;i<=n;i++){
23         cin>>w[i]>>v[i];
24     } //输入每件物品的重量和价值 
25     int m[100][100];
26     cout<<Knapsack(n,c,w,v,m); 
27     return 0; 
28 }

 

posted on 2018-11-24 17:12  huangroumin  阅读(489)  评论(0编辑  收藏  举报

导航