華爲機試練習_16:購物單(有依賴的揹包問題)

1、題目描述

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

2、思路分析

1、本題屬於依賴揹包問題:
在這裏插入圖片描述

有四種情況:
只取主件:f[i-1,j-a[i,0]]+a[i,0]*b[i,0]
取主件+附件1:f[i-1,j-a[i,0]-a[i,1]]+a[i,0]*b[i,0]+a[i,1]*b[i,1]
取主件+附件2:f[i-1,j-a[i,0]-a[i,2]]+a[i,0]*b[i,0]+a[i,2]*b[i,2]
既主件+附件1+附件2:f[i-1,j-a[i,0]-a[i,1]-a[i,2]]+a[i,0]*b[i,0]+a[i,1]*b[i,1]+a[i,2]*b[i,2]

含義:
     f[i,j]表示用j元錢,買第i類物品,所得的最大價值
     a[i,0]表示第i類物品主件的價格
     a[i,1]表示第i類物品第1個附件的價格
     a[i,2]表示第i類物品第2個附件的價格
     b[i,0],b[i,1],b[i,2]分別表示主件、第1個附件和第2個附件的重要度。
需要在滿足金額money內,買到最大價值的物品。價值=價格*重要度

2、使用二維數組加狀態方程:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            //購買物品的總錢數
            int N = scanner.nextInt();

            //希望購買的物品的數量
            int M = scanner.nextInt();

            //二維數組,第i行表示第i個物品的價值,列:0表示主鍵,1表示附件1,2表示附件2
            int[][] V = new int[M + 1][3];

            //二維數組,第i行表示第i個物品的重要程度,列:0表示主鍵,1表示附件1,2表示附件2
            int[][] P = new int[M + 1][3];

            for (int i = 1; i <= M; i++) {
                int v = scanner.nextInt();
                int p = scanner.nextInt();
                int q = scanner.nextInt();


                if (q == 0) {   //q=0代表是主件
                    V[i][0] = v;
                    P[i][0] = p;
                } else {      //q>0代表是附件,q代表附件所屬的主件編號
                    if (V[q][1] == 0) {
                        V[q][1] = v;
                        P[q][1] = p;
                    } else {
                        V[q][2] = v;
                        P[q][2] = p;
                    }
                }
            }

            //下面正式開始動態規劃算法
            int[][] dp = new int[M + 1][N + 1];
            /**
             * 1、錢夠用的時候,買不買主鍵
             * 2、錢夠用的時候,買不買主鍵、附件1
             * 3、錢夠用的時候,買不買主鍵、附件2
             * 4、錢夠用的時候,買不買主鍵、附件1、附件2
             * 5、錢不夠用的時候,只買前i-1件商品
             */
            for (int i = 1; i <= M; i++) {
                for (int j = 10; j <= N; j +=10) {
                    if (j >= V[i][0]) {
                        dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - V[i][0]] + V[i][0] * P[i][0]);
                    } else if (j >= V[i][0] + V[i][1]) {
                        dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - V[i][0] - V[i][1]] + V[i][0] * P[i][0] + V[i][1] * P[i][1]);
                    } else if (j >= V[i][0] + V[i][2]) {
                        dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - V[i][0] - V[i][2]] + V[i][0] * P[i][0] + V[i][2] * P[i][2]);
                    } else if (j >= V[i][0] + V[i][1] + V[i][2]) {
                        dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - V[i][0] - V[i][1] - V[i][2]] + V[i][0] * P[i][0] + V[i][1] * P[i][1] + V[i][2] * P[i][2]);
                    } else {
                        dp[i][j] = dp[i - 1][j];
                    }
                }
            }
            System.out.println(dp[M][N]);
        }
    }
}

不知道爲什麼通過率只有20%,總感覺牛客的測試數據有問題。

3、將二維數組優化爲一維數組加狀態方程:

import java.util.Scanner;

public class Main3 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNextInt()) {
            //總錢數
            int N = sc.nextInt();

            //總物品數
            int M = sc.nextInt();

            //二維數組,第i行表示第i個物品的價值,列:0表示主鍵,1表示附件1,2表示附件2
            int[][] V = new int[M+1][3];

            //二維數組,第i行表示第i個物品的重要程度,列:0表示主鍵,1表示附件1,2表示附件2
            int[][] P = new int[M+1][3];

            for (int i = 1; i <= M; i++) {
                int v = sc.nextInt();
                int p = sc.nextInt();
                int q = sc.nextInt();

                if (q == 0) {
                    V[i][0] = v;
                    P[i][0] = p;
                } else {
                    if (V[q][1]==0) {
                        V[q][1] = v;
                        P[q][1] = p;
                    }
                    else {
                        V[q][2] = v;
                        P[q][2] = p;
                    }
                }
            }

            //記錄最大價值
            int[] dp = new int[N+1];

            /**
             * 1、錢夠用的時候,買不買主鍵
             * 2、錢夠用的時候,買不買主鍵、附件1
             * 3、錢夠用的時候,買不買主鍵、附件2
             * 4、錢夠用的時候,買不買主鍵、附件1、附件2
             * 5、錢不夠用的時候,只買前i-1件商品
             */
            for (int i = 1; i <= M; i++)
                for (int j = N; j >= 10; j-=10) {
                    if (j >= V[i][0])
                        dp[j] = Math.max(dp[j], dp[j-V[i][0]]+V[i][0]*P[i][0]);
                    if (j >= V[i][0]+V[i][1])
                        dp[j] = Math.max(dp[j], dp[j-V[i][0]-V[i][1]]+V[i][0]*P[i][0]+V[i][1]*P[i][1]);
                    if (j >= V[i][0]+V[i][2])
                        dp[j] = Math.max(dp[j], dp[j-V[i][0]-V[i][2]]+V[i][0]*P[i][0]+V[i][2]*P[i][2]);
                    if (j >= V[i][0]+V[i][1]+V[i][2])
                        dp[j] = Math.max(dp[j], dp[j-V[i][0]-V[i][1]-V[i][2]]+V[i][0]*P[i][0]+V[i][1]*P[i][1]+V[i][2]*P[i][2]);
                }
            System.out.println(dp[N]);
        }
    }
}

優化爲一維數組後,通過率爲100%,所以還是不清楚問題在哪兒,思路相同,一個對了,一個不對。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章