經典0-1揹包問題(動態規劃)

買糖果(京東2016實習生真題)

題目描述

某糖果公司專門生產兒童糖果,它最受兒童歡迎的糖果有A1、A2兩個序列,均採用盒式包裝。包裝好的A1類糖果體積爲一個存儲單位,而包裝好的A2類糖果體積正好是A1類的兩倍。

這兩類糖果之所以廣受兒童歡迎,是因爲糖果中含有公司獨家研發的魔幻因子。A1或A2序列中的糖果,看起來包裝可能是一樣的,但因爲其中的魔幻因子含量不同被細分爲不同的產品。

臨近傳統節日,公司的糖果供不應求。作爲一個精明的糖果分銷商,小東希望能夠藉此大賺一筆,於是帶着現金開着貨車來公司提貨。貨車的容量是確定的,小東希望採購的糖果能夠儘可能裝滿貨車,且糖果的魔幻因子總含量最高。只要不超出貨車容量,糖果總可以裝入貨車中。

小東希望你能幫她解決這一問題。

在這裏插入圖片描述

import java.util.Scanner;

/**
 * 標準的0-1揹包問題,使用動態規劃解決!
 *
 *
 */
public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        while(input.hasNextInt()){

            // 1、從鍵盤獲取輸入,順便判斷容量是否能裝下所有糖果(節約內存!)
            //      若不進行判斷提交時會有內存溢出問題
            int n = input.nextInt();
            int v = input.nextInt();

            int[] nums = new int[n];
            int[] weights = new int[n];
            int temp_w = 0;
            int temp_n = 0;
            for(int i=0; i<n; ++i){
                weights[i] = input.nextInt();
                nums[i] = input.nextInt();
                temp_w += weights[i];
                temp_n += nums[i];
            }
            // 2、若總的體積和小於等於容量,則每個糖果都能裝
            if(temp_w <= v){
                System.out.println(temp_n);
                for(int i=1; i<=n; i++)
                    System.out.print(i + " ");
            }
            // 3、否則使用動態規劃。
            else {
                // 4、定義dp數組,dp[i][j]表示前0-i個糖果,容量爲j時最大魔幻因子,初始化dp[0][0] = 0
                int[][] dp = new int[n + 1][v + 1];
                // 5、狀態轉移,到第i個糖果,在容量足夠時,可以考慮裝和不裝;
                //  當裝時:dp[i][j] = dp[i-1][j-weight[i-1]]+nums[i-1];
                //  不裝時:dp[i][j] = dp[i - 1][j];
                for (int i = 1; i <= n; i++) {
                    for (int j = 0; j <= v; j++) {
                        if (j < weights[i - 1]) {
                            dp[i][j] = dp[i - 1][j];
                        } else {
                            dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + nums[i - 1]);
                        }
                    }
                }
                // 6、dp[n][v]即是最大魔幻因子
                int max = dp[n][v];
                System.out.println(max);
                if (max == 0) {
                    System.out.println("No");
                }
                // 7、打印最大魔幻因子時所裝的相應的糖果;
                // 思路:當dp[i][v] != dp[i-1][v]時,說明取了第i個糖果,既然取了第i個糖果,剩下的v=v-weights[i-1]
                else {
                    boolean[] flag = new boolean[n];
                    for (int i = n; i > 0; i--) {
                        if (dp[i][v] == dp[i - 1][v])
                            flag[i - 1] = false;
                        else {
                            flag[i - 1] = true;
                            v -= weights[i - 1];
                        }
                    }

                    for (int i = 0; i < n; ++i) {
                        if (flag[i])
                            System.out.print(i + 1 + " ");
                    }
                }
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章