多重背包的java实现 二进制优化


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();
}


}

你可能感兴趣的:(java,基础)