AcWing 5. 【Java】多重背包问题 II(二进制拆分)
原题链接
中等
作者:
tt2767
,
2020-01-12 00:53:10
,
所有人可见
,
阅读 2804
/*
拆成01背包来做,按二进制去拆
即 v,w,s = v,w,7 时:
正常拆分:-> (v,w),(v,w),(v,w),(v,w),(v,w),(v,w),(v,w)
二进制拆分:-> (v,w),(v<<1,w<<1),(v<<2,w<<2)
*/
import java.util.*;
public class Main{
void run(){
int n = jin.nextInt();
int m = jin.nextInt();
int p = 1;
for (int i = 1; i <= n ; i++){
int V = jin.nextInt();
int W = jin.nextInt();
int S = jin.nextInt();
int k = 1;
while (S > k){
v[p] = V*k;
w[p] = W*k;
S -= k;
k *= 2;
p++;
}
if (S > 0){
v[p] = V*S;
w[p] = W*S;
p ++;
}
}
int res = dp(p, m);
System.out.println(res);
}
int dp(int n, int m){
int[] f = new int[maxN];
for (int i= 1; i <= n ; i ++){
for (int j = m ; j>= v[i] ; j--){
f[j] = Math.max(f[j], f[j - v[i]] + w[i]);
}
}
return f[m];
}
int maxN = 200002;
int[] v = new int[maxN];
int[] w = new int[maxN];
Scanner jin = new Scanner (System.in);
public static void main(String[] args) {new Main().run();}
}
为什么不是N*每个si能拆出来的个数+ 左右预留的哨兵位置
这个int maxN = 200002;
怎么推算出来的
这个是随便写一个大的数, 如果要算一下的话应该是:
si * 每个si能拆出来的个数 + 左右预留的哨兵位置 = 2000 * log2(2000) + 2 <= 22002