♥
01背包
♥
情况
有N件物品和一个容量为V的背包, 每种物品均只有一件 。第 i 件物品的费用是c[i],价值是w[i]。
利用数组f[N]表示背包容量为N时,背包中的总价值。
for(int i = 1; i <= n; i++)//n为物品数量,v是背包容量上限
{
for(int j = v; j >= c[i]; j--)
{//此处用逆序,防止当v>=c[i]时,会在f[x](x>=2*c[i])时计算取两件该物品的情况)
f[j] = max(f[j], f[j-c[i]] + w[i]);
}
}
♥
完全背包
♥
情况
有N件物品和一个容量为V的背包, 每种物品均有无限件 。
for(int i = 1; i <= n; i++)
{
for(int j = c[i]; j <= v; j++)
{//此处用顺序,因物品有无限个,可包含多取情况
f[j] = max(f[j], f[j-c[i]]+w[i]);
}
}
♥
多重背包
♥
情况
有N件物品和一个容量为V的背包, 每种物品均有n[i]件 。
for(int i = 1; i <= N; i++)
{
for(int k = 1; k <= n[i]; k++)
{//通过循环k次,达到判断装 0~k 个该物品情况
for(int j = c[i]; j <= v; j++)
{//这里用逆序,防止变成无限个计算
f[j] = max(f[j], f[j-c[i]]+w[i]);
}
}
}
♥
二进制优化(二进制分解)
原理
例如:7的二进制为 111,可分解为 001 010 100 三个数,即 1 2 4。这三个数可以组合为 1 ~ 7 内所有数。基于该思想将 多件物品 转化为 多种一件物品。
cin >> s >> ci >> wi;//s 数量,ci单件物品费用,vi单件物品价值
for(int k = 1; k <= s; k++)
{
c[cnt] = k*ci;
w[cnt++] = k*wi;
s -= k;
}
if(s>0)
{
c[cnt] = s*ci;
w[cnt++] = s*wi;
}
♥
♥
代码
#include <iostream>
#include <math.h>
#include <cstring>
using namespace std;
const int N = 505; // 比题目给出n的范围大,
//因为将多件物品转化为了多种物品
int n, m;
int c[N], w[N], f[N];
int main( )
{
int t;
scanf("%d",&t);
while( t-- )
{
memset(f, 0, sizeof(f));
scanf("%d%d",&m,&n);
int ci, wi, s, cnt = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d%d%d",&ci,&wi,&s);
for(int k = 1; k <= s; k <<= 1)
{
c[++cnt] = k*ci;
w[cnt] = k*wi;
s -= k;
}
if( s>0 )
{
c[++cnt] = s*ci;
w[cnt] = s*wi;
}
}
for(int i = 1; i <= cnt; i++)
{
for(int j = m; j >= c[i]; j--)
{
f[j] = max(f[j], f[j-c[i]]+w[i]);
}
}
int ans = 0;
for(int i = 0; i <= m; i++) ans = max(ans, f[i]);
printf("%d\n",ans);
}
return 0;
}