看网上面好多标着标签写着【通俗易懂,超基础讲解】我居然都看不懂。
所以理解了以后自己来写一个。
问题描述:假如有5个物品,其重量分别是{2,2,6,5,4},价值分别是{6,3,5,4,6},背包容量为10,利用动态规划求解0/1背包问题。
int w[5]={2,2,6,5,4};
int v[5]={6,3,5,4,6};
int C=10;
所以就是这样。
大家都知道0/1背包问题怎么解决。就是把每个物品,装或者不装进行一次判断,求其最大价值。
但是看到图就懵逼了。 图用V(i,j)表示。
i/j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
2 | 0 | 0 | 6 | 6 | 9 | 9 | 9 | 9 | 9 | 9 | 9 |
3 | 0 | 0 | 6 | 6 | 9 | 9 | 9 | 9 | 11 | 11 | 14 |
4 | 0 | 0 | 6 | 6 | 9 | 9 | 9 | 10 | 11 | 13 | 14 |
5 | 0 | 0 | 6 | 6 | 9 | 9 | 9 | 12 | 12 | 15 | 15 |
简单说,表中 i 是前i个物品,表中 j 是背包容量。i=0表示不装入物品时,j=0表示背包容量为0。V(i,j)表示当背包容量为 j 时,装入前 i 个物品的最大价值。这是一个局部最优解,已经考虑了装不装入的所以情况。V(1,2)表示,当背包容量为2时,只考虑装入前一个物品的情况下的最大价值,表中V(5,10)为最后所求的最大价值。
动态规划的原理是局部最优。
拿到这个递推关系。j(背包容量)够的时候考虑到底装不装入,不够时直接等于前面那个的价值。
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]}
j>=w(i) V(i,j) 是此时我考虑到 j(背包容量) 可以放的下我的第 i 物品,我要开始尝试怎么放价值最大。
V(i-1,j) 表示不装入物品,价值还和前面那个一样。
V(i-1,j-w[i])+v[i] 表示装入第i个物品。 就是说我现在要空出一个w[i] 的空间来放我的第i个物品(+v[i] ),但我放之前还要保证余下的空间j-w[i] 任然是一个局部最优解。就是 V(i-1,j-w[i]) 它是我考虑 前i-1物品,在j-w[j]余下的空间里,的最大价值。
例如,我在装第三个物品时考虑。它的w(重量)=6,v=5。j(背包容量)=1,2,3,4,5的时候都装不下它,所以和装入前两个物品时一致。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
3 | 0 | 0 | 6 | 6 | 9 | 9 | 9 | 11 |
6>=6 V(3,6)=max{V(2,6),V(2,0)+5} 比较之前6个空间装前两个物品(v=9),和我现在空出来6个空间装我的第三个物品(v=5),价值哪个大。当然是9大,所以不装入。 继续到 j=8的时候,出现了新的情况,我可以考虑空出来6个空间装入第三个物品,然后还剩两个空间。先比一下 8>=6 V(3,8)=max{V(2,8),V(2,2)+5} 这里的V(2,2)就是背包容量为2时,且只考虑装入两个物品时的最优解。V(2,8)=6 V(2,2)+5=6+5=11 11大了。
V(5,10) 同理。一行一行算就ok了。
#include<iostream>
#include<stdio.h>
#include<algorithm>
#define maxn 50000
using namespace std;
int V[50][50];
int x[6];
void KnapSack(int w[],int v[],int n,int C){
int i,j;
for(i=0;i<=n;i++){
V[i][0]=0;
}
for(j=0;j<=C;j++){
V[0][j]=0;
}
for(i=1;i<=n;i++)
for(j=1;j<=C;j++)
if(j<w[i-1]) V[i][j]=V[i-1][j];
else V[i][j]=max(V[i-1][j],V[i-1][j-w[i-1]]+v[i-1]);
for(j=C,i=n;i>0;i--){
if(V[i][j]>V[i-1][j]){
x[i]=1;
j=j-w[i-1];
}
else x[i]=0;
}
for(int i=1;i<=n;i++){
cout<<x[i];
}
cout<<endl;
cout<<V[n][C];
}
int main(){
int w[5]={3,2,1,4,5};
int v[5]={25,20,15,40,50};
int C=6;
int n=5;
KnapSack(w,v,n,C);
}