背包问题
背包问题主要由三类:
- 01背包
- 完全背包
- 多重背包
1、01背包(使用滚动数组优化)
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int t = sc.nextInt(); for (int k = 1; k <= t; k++) { int N = sc.nextInt(); // 商品个数 int V = sc.nextInt(); // 总花销 int[] cost = new int[N]; // 单个花销 int[] val = new int[N]; // 单个价值 for (int i = 0; i < N; i++) val[i] = sc.nextInt(); for (int i = 0; i < N; i++) cost[i] = sc.nextInt(); int[] dp = new int[V+1]; // 初始化 for (int i = 0; i <= V; i++) dp[i] = 0; for (int i = 1; i <= N; i++) { ZeroOnePack(dp, V, cost[i-1], val[i-1]); } System.out.printf("%d%n", dp[V]); } } public static void ZeroOnePack(int[] dp, int V, int C, int W) { for (int i = V; i >= C; i--) { dp[i] = Math.max(dp[i], dp[i-C] + W); } } }
2、完全背包
// 完全背包 // 状态转移方程:F[i,v] = max{F[i-1,v], F[i,v-Ci] + Wi} v -> Ci..V public static void CompletePark(int[] dp, int V, int C, int W) { for (int i = C; i <= V; i++) { dp[i] = Math.max(dp[i], dp[i-C] + W); } }
import java.util.*; public class Main { static final int MAXN = 0x3f3f3f3f; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int t = sc.nextInt(); for (int k = 1; k <= t; k++) { int minV = sc.nextInt(); int maxV = sc.nextInt(); int V = maxV - minV; // 总花销 int N = sc.nextInt(); // 商品的种类数量 int[] cost = new int[N]; // 单个花销 int[] val = new int[N]; // 单个价值 for (int i = 0; i < N; i++) { val[i] = sc.nextInt(); cost[i] = sc.nextInt(); } int[] dp = new int[V+1]; // 求背包装满的情况下,总背包的最小值 Arrays.fill(dp, MAXN); dp[0] = 0; for (int i = 1; i <= N; i++) { CompletePark(dp, V, cost[i-1], val[i-1]); } if(dp[V] != MAXN) System.out.printf("The minimum amount of money in the piggy-bank is %d.%n", dp[V]); else System.out.printf("This is impossible.%n"); } } // 完全背包 // 状态转移方程:F[i,v] = max{F[i-1,v], F[i,v-Ci] + Wi} v -> Ci..V public static void CompletePark(int[] dp, int V, int C, int W) { for (int i = C; i <= V; i++) { dp[i] = Math.min(dp[i], dp[i-C] + W); } } }
3、多重背包
// 多重背包 public static void MultiplePack(int[] dp, int V, int C, int W, int M) { if (C * M >= V) { CompletePark(dp, V, C, W); } else { // 使用二进制转换为0-1背包 // 1 + 2^1 + 2^2 + ... + 2^(k-1) + (M - 2^k + 1) = M int k = 1; while (k < M) { ZeroOnePack(dp, V, k*C, k*W); M -= k; k <<= 1; } if (M > 0) { // 如果M有剩余,可以转化为1个价值为M*W,重量为M*C的物品,转化为01背包问题 ZeroOnePack(dp, V, M*C, M*W); } } }
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int t = sc.nextInt(); for (int k = 1; k <= t; k++) { int V = sc.nextInt(); // 总金额 int N = sc.nextInt(); // 商品的种类数量 int[] cost = new int[N]; // 单个花销 int[] val = new int[N]; // 单个价值 int[] num = new int[N]; // 单个物品的数量 for (int i = 0; i < N; i++) { cost[i] = sc.nextInt(); val[i] = sc.nextInt(); num[i] = sc.nextInt(); } int[] dp = new int[V+1]; for (int i = 0; i <= V; i++) dp[i] = 0; for (int i = 1; i <= N; i++) { MultiplePack(dp, V, cost[i-1], val[i-1], num[i-1]); } System.out.printf("%d%n", dp[V]); } } public static void ZeroOnePack(int[] dp, int V, int C, int W) { for (int i = V; i >= C; i--) { dp[i] = Math.max(dp[i], dp[i-C] + W); } } // 完全背包 // 状态转移方程:F[i,v] = max{F[i-1,v], F[i,v-Ci] + Wi} v -> Ci..V public static void CompletePark(int[] dp, int V, int C, int W) { for (int i = C; i <= V; i++) { dp[i] = Math.max(dp[i], dp[i-C] + W); } } // 多重背包 public static void MultiplePack(int[] dp, int V, int C, int W, int M) { if (C * M >= V) { CompletePark(dp, V, C, W); } else { // 使用二进制转换为0-1背包 // 1 + 2^1 + 2^2 + ... + 2^(k-1) + (M - 2^k+ 1) = M int k = 1; while (k < M) { ZeroOnePack(dp, V, k*C, k*W); M -= k; k <<= 1; } if (M > 0) { // 如果M有剩余,可以转化为1个价值为M*W,重量为M*C的01背包问题 ZeroOnePack(dp, V, M*C, M*W); } } } }
作者:Ryanjie
出处:http://www.cnblogs.com/ryanjan/
本文版权归作者和博客园所有,欢迎转载。转载请在留言板处留言给我,且在文章标明原文链接,谢谢!
如果您觉得本篇博文对您有所收获,觉得我还算用心,请点击右下角的 [推荐],谢谢!