1. 程式人生 > >多重揹包的java實現 二進位制優化

多重揹包的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<N+1;i++){
// for(int j=0;j<W+1;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();
}


}