01背包冲鸭!!!
好吧他死了,考虑每一个物品体积都为(b*2^a)尝试进制优化
首先设背包大小为(m)
设(f_{i,j})为背包大小最高位为(j*2^i)时最大价值
也就是说,设现在考虑的物品编号为(k),则背包大小为(j*2^i)+(()(w_k)&(((1<<i)-1))))
原来我们是枚举整个背包大小,而现在我们不再考虑低于第(i)位的确切数值
比如当(w_k=1001),(i=5,j=1),背包大小为(11001)(除了(i),以上均为二进制)
转移则为(f_{i,j}=max(f_{i,j},f_{i,j-d}+f{i-1,2*d|((m>>(i-1))-1)}))
就是说考虑从(i-1)处转移过来(2^i*d)大小的体积,由于(i)减了(1),(d)相应要乘(2)
就是(f_{i-1,2*d}),考虑背包自身上限,还可以加上一个(2*d+((m>>(i-1))-1)
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const ll N=1005;
ll n,m,f[35][N],a[N],b[N],top;
int main(){
scanf("%lld%lld",&n,&m);
while(n!=-1&&m!=-1){
top=0;
memset(f,0,sizeof f);
for(ll i=1;i<=n;i++){
ll cnt=0,x;
scanf("%lld%lld",&a[i],&b[i]),x=a[i];
while(x%2==0){x/=2,cnt++;}
for(ll j=1000;j>=x;j--){
f[cnt][j]=max(f[cnt][j],f[cnt][j-x]+b[i]);
}
}
for(ll i=m;i>0;i/=2)top++;
top--;
for(ll i=1;i<=top;i++){
for(ll j=1000;j>=0;j--){
for(ll k=0;k<=j;k++){
f[i][j]=max(f[i][j],f[i][j-k]+f[i-1][min(1000*1ll,(k*2)|((m>>(i-1))&1))]);
}
}
}
printf("%lld
",f[top][1]);
scanf("%lld%lld",&n,&m);
}
}
代码比较憨,请见谅