0-1 背包实际应用

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 背包问题

  1. 游戏数量 --> 物品数量
  2. 计划天数 --> 背包重量
  3. 游戏成就值 --> 物品价值
  4. 游戏耗费天数 --> 物品重量

3、代码实现

  1. 代码

    /**
     * @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 2
    10 1
    20 2
    20
    

你可能感兴趣的:(面试算法,动态规划,0-1背包)