0-1 背包实际应用
1、题目要求
From DJ
有许多程序员都热爱玩游戏,而小J自称为游戏王,曾玩过几百种游戏,几乎所有能玩到的游戏大作都玩遍了。随着时间的推移,他发觉已经没有游戏可以让他玩了!于是他想改玩一些古老的游戏,以成为真正的“游戏王”。他希望在接下来的一段时间内将过去出的游戏全部玩一遍,但是毕竟时间有限,因此他感到很苦恼。
于是他想到一个计划,他先将每个游戏标上一个成就值,同时对每个游戏都估算一个通关所需要的天数,他计划在未来X天内让自己玩游戏的成就达到最大,那么他应该怎么做计划呢?(假设每个游戏最多只计划玩一遍,而且每个游戏必须玩完通关才能取得成就值,且通关每个游戏最小时间单位是1天)
输入描述
第一行输入两个整数N和X,中间用空格隔开,其中N表示游戏的数目N(1<=N<=10),X表示计划玩游戏的总时间天数 (1<=X<=1000)。
第二行输入第1个游戏的成就值A1(0<=A1<=10000) 和 通关所需要花费时间B1天 (1<=Bi<=500) 中间用空格隔开。
第N+1行输入第N游戏的成就值An(0<=An<=10000) 和 通关所需要花费时间Bn天(1<=Bn<=500) 中间用空格隔开
输出描述
可以达到成就之和的最大值。
示例 1
样例输入
2 2
10 1
20 2
样例输出
20
示例 2
输入样例二:
3 4
10 2
18 3
10 2
输出样例二:
20
2、代码思路
题目一看就是 0-1 背包问题
- 游戏数量 --> 物品数量
- 计划天数 --> 背包重量
- 游戏成就值 --> 物品价值
- 游戏耗费天数 --> 物品重量
3、代码实现
-
代码
/** * @ClassName PlayGameDemo * @Description TODO * @Author Heygo * @Date 2020/8/16 19:37 * @Version 1.0 */ public class PlayGameDemo { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int gameCounts; // 游戏数量(物品数量) int planDays; // 计划天数(背包重量) String line = scanner.nextLine(); gameCounts = Integer.parseInt(line.split(" ")[0]); planDays = Integer.parseInt(line.split(" ")[1]); int[] achievement = new int[gameCounts + 1]; // 游戏成就值(物品价值) int[] costDay = new int[gameCounts + 1]; // 游戏耗费天数(物品重量) for (int i = 0; i < gameCounts; i++) { line = scanner.nextLine(); achievement[i + 1] = Integer.parseInt(line.split(" ")[0]); costDay[i + 1] = Integer.parseInt(line.split(" ")[1]); } int maxAchievement = knapsack(planDays, gameCounts, costDay, achievement); System.out.println(maxAchievement); } /** * 0-1 背包问题 * * @param W 背包的重量 * @param N 现有物品的数量 * @param wt 物品的重量 * @param val 物品的价值 * @return 背包中物品的最大价值 */ public static int knapsack(int W, int N, int[] wt, int[] val) { // dp[i][w] 表示:对于前 i 个,当背包容量为 w 时,能放下的最大价值为 dp[i][w] int[][] dp = new int[N + 1][W + 1]; // 从第一个物品开始,一个一个放入物品 for (int i = 1; i <= N; i++) { // 背包重量逐渐增大,尝试放入物品 for (int w = 1; w <= W; w++) { // dp[][] 数组中的 i 对应 wt[] 和 val[] 数组中的 i if (w - wt[i] < 0) { // 当前背包容量装不下,只能选择不装入背包,选择上一次的最大价值作为这次的最大价值 dp[i][w] = dp[i - 1][w]; } else { /* 当前背包容量能装下: w - wt[i] :装入当前物品,背包还剩余多少空间(重量) dp[i - 1][w - wt[i]] :重量为 w - wt[i] 的背包最多能装下多大价值的物品 val[i] :当前物品的价值 (dp[i - 1][w - wt[i]] + val[i]) :装下当前物品后,背包中物品的最大价值 dp[i - 1][w] :上一次的最大价值 尝试着将当前物品放入背包,和上一次的价值比,看看谁大谁小,选价值大的 */ dp[i][w] = Math.max((dp[i - 1][w - wt[i]] + val[i]), dp[i - 1][w]); } } } for (int[] ints : dp) { System.out.println(Arrays.toString(ints)); } return dp[N][W]; } }
-
程序运行结果
2 2 10 1 20 2 20