import java.util.Scanner;
public class 多重背包 {
private static int[] dp;
/**
* 输入
*
* 第1行,2个整数,N和W中间用空格隔开。N为物品的种类,W为背包的容量。(1 <= N <= 100,1 <= W <= 50000) 第2 -
* N + 1行,每行3个整数,Wi,Pi和Ci分别是物品体积、价值和数量。(1 <= Wi, Pi <= 10000, 1 <= Ci <=
* 200)
*
* 输出
*
* 输出可以容纳的最大价值。
*
* 输入示例
*
* 3 6 2 2 5 3 3 8 1 4 1
*
* 输出示例
*
* 9
*/
public static void main(String[] args) {
/**
* 输入
*
* 第1行,2个整数,N和W中间用空格隔开。N为物品的种类,W为背包的容量。(1 <= N <= 100,1 <= W <= 50000)
* 第2 - N + 1行,每行3个整数,Wi,Pi和Ci分别是物品体积、价值和数量。(1 <= Wi, Pi <= 10000, 1 <=
* Ci <= 200)
*
* 输出
*
* 输出可以容纳的最大价值。
*
* 输入示例
*
* 3 6 2 2 5 3 3 8 1 4 1
*
* 输出示例
*
* 9
*/
Scanner in = new Scanner(System.in);
int N = in.nextInt();// 物品的种类 //(1 <= N <= 100,1 <= W <= 50000)
int W = in.nextInt();// 背包的容量
int index = 0;
int[] weight = new int[N];// 重量
int[] value = new int[N];// 价值
int[] count = new int[N];// 数量
while (index < N) {
weight[index] = in.nextInt();
value[index] = in.nextInt();
count[index] = in.nextInt();
index++;
}
dp = new int[W + 1];
// 初值 dp[0][j]=0;
for (int i = 1; i < N + 1; i++) {
if (count[i - 1] * weight[i - 1] >= W) {// 相当于无限数量的第i中物品
// 完全背包:该类物品原则上是无限供应,
// 此时满足条件Weight[i] * Num[i] >= V时,
// 表示无限量供应,直到背包放不下为止.
completePack(weight[i - 1], value[i - 1], W,i);
} else {
int m = count[i - 1];
for (int k = 1; k <= m;) {
zeroOnePack(k * weight[i - 1], k * value[i - 1], W,i);
// dp[i][j] = Math.max(dp[i - 1][j - weight[i - 1] * k] +
// value[i - 1] * k, dp[i][j]);
m -= k;
k *= 2;
}
// 分解二进制剩余的 Cn拆成 Cn=1+2+4+8+...+(Cn-sum)。
// 这里sum表示前面的数字之和,例如 按照规律加到第m个数,发现已经大于Cn,那么
// sum就表示从 1+2+4+8+.....+ 2^(m-2)。 我们可以检验, 在[1,Cn]中任意的数
// 我们都可以在这个序列中找到若干数相加得到。
zeroOnePack(weight[i - 1] * m, value[i - 1] * m, W,i);
}
}
// System.out.println();
// for(int i=0;i
// for(int j=0;j
//
// System.out.print("dp["+i+","+j+"]="+dp[j]+"\t");
// }
// System.out.println();
// }
System.out.println(dp[W]);
}
/**
* f[v]:表示把前i件物品放入容量为v的背包中获得的最大收益。 f[v] = max(f[v],f[v - Weight[i]] +
* Value[i]); v的为逆序
*
* @param weight
* 物品的重量
* @param value
* 物品的收益
* @param W
* 背包容量
*/
private static void zeroOnePack(int nweight, int nvalue, int W,int i) {
for (int j = W; j >= nweight; j--) {
// dp[i][j] = Math.max(dp[i - 1][j - weight[i - 1] * k] + value[i -
// 1] *
// k, dp[i][j]);
dp[j] = Math.max(dp[j - nweight] + nvalue, dp[j]);
System.out.print("dp["+i+","+j+"]="+dp[j]+"\t");
}
System.out.println();
}
/**
* f[v]:表示把前i件物品放入容量为v的背包中获得的最大收益。 f[v] = max(f[v],f[v - Weight[i]] +
* Value[i]); v的为增序
*
* @param weight
* 物品的重量
* @param value
* 物品的收益
* @param W
* 背包容量
*/
private static void completePack(int nweight, int nvalue, int W,int i) {
for (int j = nweight; j <= W; j++) {
dp[j] = Math.max(dp[j - nweight] + nvalue, dp[j]);
System.out.print("dp["+i+","+j+"]="+dp[j]+"\t");
}
System.out.println();
}
}