分析01背包:
01背包(ZeroOnePack): 有N件物品和一个容量为V的背包。(每种物品均只有一件)第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
特点:每种物品仅有一件,可以选择放或不放。
- 用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
把这个过程理解下:在前i件物品放进容量v的背包时,
它有两种情况:
第一种是第i件不放进去,这时所得价值为:f[i-1][v]
第二种是第i件放进去,这时所得价值为:f[i-1][v-c[i]]+w[i]
for(i = 1; i<=n; i++) { for(j = v; j>=c[i]; j--) //在这里,背包放入物品后,容量不断的减少,直到再也放不进了 { f[i][v] = max(f[i-1][v],f[i-1][v-c[i]]+w[i]); } }
|
用二位数组存储的,可以把空间优化,用一位数组存储。
用f[0..v]表示,f[v]表示把前i件物品放入容量为v的背包里得到的价值。把i从1~n(n件)循环后,最后f[v]表示所求最大值。
for I = 1..N for v = V..0
f[v] = max{ f[v] , f[v-c[i]]+w[i] };
|
#include <stdio.h>
#include <stdlib.h>
using namespace std;
#define maxn 1000
int ww[maxn],vv[maxn];
int ac[maxn];//ac[v]表示当前状态是容量为v的背包所得价值
int n,m,t;
int main(){
scanf("%d",&t);
while(t--){
memset(ac,0,sizeof(ac));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",&ww[i]);
for(int i=1;i<=n;++i)
scanf("%d",&vv[i]);
for(int i=1;i<=n;++i)
I=1,ac[]表示编号为0的数值(空背包 I=2,ac[]表示编号为的数值(背包上一次放的物品)
|
//逆序!
for(int j=m; j>=ww[i]; --j) {
//(背包中放入第i件物品)容量为j-ww[i]的背包所得价值+第i件物品价值 与 容量为j的物品价值
if(ac[j-ww[i]]+vv[i] > ac[j])
ac[j] = ac[j-ww[i]]+vv[i]; }
printf("%d\n",ac[m]);
}
return 0;
}