卧薪尝胆,厚积薄发。
HNOI2007 梦幻岛宝珠
Date: Fri Oct 19 17:28:55 CST 2018 In Category: NoCategory

Description:

$N$ 个物品,每个物品都有重量和价值。选一些物品总重量不超过 $W$ 且总价值最大。
$N\leqslant100,W\leqslant2^{30},$ 并且保证每个物品的重量符合 $a\times2^b$ 。

Solution:

既然告诉 $w[i]=a\times2^b$ 那就按二进制位考虑,设 $f_1[i][j]$ 表示只考虑 $b=i$ 的物品 $a$ 的和为 $j$ 所能获得的最大价值,这个可以把物品按 $b$ 分组然后每组做 $01$ 背包,再设 $f_2[i][j]$ 表示所有 $b<i$ 的物品都已考虑完,都合并到 $i$ 这一位上需要的容积为 $j\times 2^i$ 能获得的最大价值,转移时发现 $f_2[i-1][j]$ 等价于 $f_2[i][\lceil\frac{j-(m的第i位是1)}2\rceil]$ ,可以把每个 $f_2[i][j]$ 都像这样提高一位,看成一个物品,然后在 $f_1[i][j]$ 的基础上再做一个类似分组背包的东西,因为只能选一个 $f_2$ ,否则会选重,但是由于有重量为 $0$ 的物品存在所以需要用一个 $g[i]$ 辅助转移。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cctype>
#include<cstring>
using namespace std;
int n,m;
#define R register
inline int rd()
{
R int res = 0,f = 1;
R char c = getchar();
while(!isdigit(c))
{
if(c == '-')f = -1;
c = getchar();
}
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res * f;
}
#define MAXN 110
int w[MAXN],v[MAXN];
struct item{int w,v;};
vector<item> s[32];
#define MAX 1000
int f[32][MAX + 10];
int g[MAX + 10];
int main()
{
while(scanf("%d%d",&n,&m) && n != -1 && m != -1)
{
for(R int i = 0;i <= 31;++i)s[i].clear();
for(R int i = 1;i <= n;++i)
{
w[i] = rd();v[i] = rd();
}
for(R int i = 1;i <= n;++i)
{
R int cnt = 0;
while(w[i] % 2 == 0)
{
++cnt;
w[i] /= 2;
}
s[cnt].push_back((item){w[i],v[i]});
}
memset(f,0xc0,sizeof(f));
for(R int i = 0;i <= 31;++i)
{
f[i][0] = 0;
for(R vector<item>::iterator it = s[i].begin();it != s[i].end();++it)
{
for(R int j = MAX;j >= it -> w;--j)
{
f[i][j] = max(f[i][j],f[i][j - it -> w] + it -> v);
}
}
}
for(R int i = 0;i <= 30;++i)
{
memset(g,0xc0,sizeof(g));
for(R int k = MAX;k >= 0;--k)
{
for(R int j = 0;j <= MAX;++j)
{
R int vi = (j - ((m >> i) & 1) + 1) / 2;
if(k >= vi)g[k] = max(g[k],f[i + 1][k - vi] + f[i][j]);
else break;
}
}
for(R int k = MAX;k >= 0;--k)f[i + 1][k] = g[k];
}
cout << f[31][0] << endl;
}
return 0;
}
In tag: DP-背包
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡