华为在线编程题系列-16-购物单

问题描述:

问题描述
问题描述

1. 问题涉及知识点.

  • 动态规划.

2. 自己解法.

  • 先对数据进行合并.
(原始数据)
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0

(因为最后结果是需要和重要性进行加权的,所以提前进行加权)
_______________
800 1600 0 
400 2000 1 
300 1500 1 
400 1200 0 
500 1000 0 

(因为购买主物品时候必须购买附属品,所以把附属品加再主物品上)
_______________
(构成动态规划处理数据)
1500 5100 
400 1200 
500 1000 
_______________
2200
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int allMoney = scanner.nextInt();
        int N = scanner.nextInt();
        int [][]intArr = new int[N][3];
        for(int i=0;i<N;i++){
            intArr[i][0] = scanner.nextInt(); // 价格
            intArr[i][1] = intArr[i][0]*scanner.nextInt(); // 价格 *重要度(评估的价值)
            intArr[i][2] = scanner.nextInt(); // 附属属性
        }

        int result = getResult(allMoney,intArr);
        System.out.println(result);
    }

    private static int getResult(int allMoney, int[][] intArr) {
        int N = intArr.length;
//        System.out.println("_______________");
//        Utils.printIntArr2(intArr,N,3);
        // 把附属品的价格和价值合并再主件上
        int [][]intArr_2  = new int[N+1][2];
        int intArr_2Index = 1;
        for (int[] anIntArr : intArr) {
            if (anIntArr[2] != 0) {
                intArr_2[anIntArr[2] - 1][0] = intArr_2[anIntArr[2] - 1][0] + anIntArr[0];
                intArr_2[anIntArr[2] - 1][1] = intArr_2[anIntArr[2] - 1][1] + anIntArr[1];
            } else {
                intArr_2[intArr_2Index][0] = anIntArr[0];
                intArr_2[intArr_2Index][1] = anIntArr[1];
                intArr_2Index++;
            }
        }

        return DP(intArr_2,allMoney,intArr_2Index);
    }
    private static int DP(int[][] intArr, int allMoney,int intArr_2Index) {
//        System.out.println("_______________");
//        Utils.printIntArr2(intArr,intArr_2Index,2);
        // 1 建立数组
        int[][] keyMap = new int[allMoney+1][intArr_2Index];//java会给数组默认为0.所以不用初始化.
        // 2 建立keyMap.
        for(int j=1;j<keyMap.length;j++){
            for(int i=1;i<keyMap[j].length;i++){
                if(j<intArr[i][0]){
                    // 不装
                    keyMap[j][i] = keyMap[j][i];
                }else {
                    //装
                    keyMap[j][i] = Math.max(keyMap[j][i-1],intArr[i][1]+keyMap[j-intArr[i][0]][i-1]);
                }
            }
        }
//        System.out.println("_______________");
//        Utils.printIntArr2(keyMap,allMoney+1,intArr_2Index);
        return keyMap[keyMap.length-1][keyMap[0].length-1];
    }
}

3. 优质答案.

链接:https://www.nowcoder.com/questionTerminal/f9c6f980eeec43ef85be20755ddbeaf4
来源:牛客网

import java.util.Scanner;

public class Main{

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int sum_money = 0;
        int num = 0;           
        sum_money=sc.nextInt();
        num=sc.nextInt();
        int price[]=new int[num+1];
        int val[]=new int[num+1];
        int[] q = new int[num+1];
        for (int i = 1; i <= num; i++) {
            price[i]=sc.nextInt();
            val[i]=sc.nextInt()*price[i];
            q[i]=sc.nextInt();
        }
        int[][] dp=new int[num+1][sum_money+1];
/*
* 初始值java默认赋值为0,其中dp[0][0...sum_money]为0,从dp[1][0...sum_money]
  计算第1行,代表第一件物品
dp[i][sum_money] : 前i个物体放入容量为sum_money的背包的最大价值;
dp[i-1][sum_money] : 前i-1个物体放入容量为sum_money的背包的最大价值;
dp[i-1][sum_money-price[i]] : 前i-1个物体放入容量为sum_money-price[i]的背包的最大价值;
dp[i][sum_money]=Math.max{dp[i-1][sum_money-price[i]]+val[i] , dp[i-1][sum_money]}
*/
        for (int i = 1; i <=num; i++) {
            for (int j = 1; j <= sum_money; j++) {
                if(q[i]==0)
                {
                    if(price[i]<=j)
                        dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-price[i]]+val[i]);
                }
                if(q[i]>0)
                {
                    if(price[i]+price[q[i]]<=j)
                        dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-price[i]-price[q[i]]]+val[i]+val[q[i]]);
                }
            }

        }
        System.out.println(dp[num][sum_money]);
    }
}

4. 本题总结.

这个题采用动态规划,动态规划的思想是把不同时刻的最优质通过数组的形式记录下来.再后面计算的时候直接调用前面的值,而不用再次计算.
动态规划的准确率 取决于数据和构造的数组((容量+1)*(数据量+1))这里的数据量一定要注意是从0开始还是从1开始,如果是从1开始就不用+1.

猜你喜欢

转载自blog.csdn.net/u012222078/article/details/80215963