题解 | #购物单#

购物单

https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static int[][] dpFlag;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt() / 10;  // 总钱数 N<3200
        int m = sc.nextInt();  // 可购买的物品的个数 m <60
        Map<Integer, List<Integer>> data1 = new HashMap<>(); // 0:价格  1:重要度(1-5) 2:主件还是附件
        Map<Integer, List<Integer>> data2 = new HashMap<>(); // 0:价格  1:重要度(1-5) 2:主件还是附件
        for (int i = 0; i < m; i++) {
            List<Integer> tmp = new ArrayList<>();
            for (int j = 0; j < 3; j++) {
                if(j == 0){
                    tmp.add(sc.nextInt() / 10);  // 价格都是10的倍数,故除10,减少dpFlag存储空间
                } else {
                    tmp.add(sc.nextInt());
                }
            }
            if (tmp.get(2) == 0) {
                data1.put(i + 1, tmp);
            } else {
                data2.put(i + 1, tmp);
            }
        }
        int ret = gwd(data1, data2, N, m);
        System.out.println(ret * 10);  // 结果要乘10
    }

    private static int gwd(Map<Integer, List<Integer>> data1,
                           Map<Integer, List<Integer>> data2, int N, int m) {
		// 处理数据,主商品放入data1,存在附件,则通过value的的list查找,如果list.size == 3,表示没有附件,list.size == 4,有1个附件,list.size == 5,有2个附件,data2存储附件信息,通过list列表数据进行查找
        for (Integer key : data2.keySet()) {
            int q = data2.get(key).get(2);
            data1.get(q).add(key);
        }
        Set<Integer> tmp = new HashSet<>();
        for (Integer key : data1.keySet()) {
            tmp.add(key);
        }
        for (Integer key1 : tmp) {
            data1.put(key1 + 60, data1.get(key1));
            data1.remove(key1);
        }
        int index = 1;
        tmp.clear();
        for (Integer key : data1.keySet()) {
            tmp.add(key);
        }
        for (Integer key1 : tmp) {
            data1.put(index++, data1.get(key1));
            data1.remove(key1);
        }
        dpFlag = new int[N + 1][data1.size() + 1];
        for (int i = 0; i <= N; i++) {
            for (int j = 0; j <= data1.size(); j++) {
                dpFlag[i][j] = -1;
            }
        }
        return dp(data1, data2, N, data1.size());
    }

    private static int dp(Map<Integer, List<Integer>> data1,
                          Map<Integer, List<Integer>> data2, int N, int m) {
        if (m == 0) {
            return 0;
        } else if (N == 0) {
            return 0;
        }
        if (dpFlag[N][m] != -1) {  // 查找记录,找到记录不再计算
            return dpFlag[N][m];
        }

        List<Integer> zhu = data1.get(m);
        int v1 = 0, v2 = 0, v3 = 0, w1 = 0, w2 = 0, w3 = 0; // 商品价格和重要度
        int b0 = 0, b1 = 0, b21 = 0, b22 = 0, b3 = 0; 
	    // 购买0个商品的最大满意度,只买1个主商品,买主商品和附件1,买主商品和附件2,买主商品和附件1、附件2
        int ret = 0; // 记录计算数据
        b0 = dp(data1, data2, N, m - 1);   // b0计算是任意条件需要的,提到最外处
        if (zhu.size() == 3) { // 该主商品没有附件
            v1 = zhu.get(0);
            w1 = zhu.get(1);
            if (N >= v1) {     // 买的起主商品
                b1 = dp(data1, data2, N - v1, m - 1) + v1 * w1;
                ret = Math.max(b0, b1);
                dpFlag[N][m] = ret;
                return ret;
            } else {           // 买不起
                dpFlag[N][m] = b0;
                return b0;
            }
        } else if (zhu.size() == 4) {  // 该主商品有1个附件
            v1 = zhu.get(0);
            w1 = zhu.get(1);
            v2 = data2.get(zhu.get(3)).get(0);
            w2 = data2.get(zhu.get(3)).get(1);
            if (N >= v1) {            // 分支判断,减少b1重复计算
                b1 = dp(data1, data2, N - v1, m - 1) + v1 * w1;
            }
            if (N >= v1 + v2) {      // 买的起主商品1和唯一附件
                b21 = dp(data1, data2, N - v1 - v2, m - 1) + v1 * w1 + v2 * w2;
                ret = Math.max(Math.max(b0, b1), b21);
                dpFlag[N][m] = ret;
                return ret;
            } else if (N >= v1) {   // 只买的起主商品1
                ret = Math.max(b0, b1);
                dpFlag[N][m] = ret;
                return ret;
            } else {                // 买不起商品
                dpFlag[N][m] = b0;
                return b0;
            }
        } else {
            v1 = zhu.get(0);
            w1 = zhu.get(1);
            v2 = data2.get(zhu.get(3)).get(0);
            w2 = data2.get(zhu.get(3)).get(1);
            v3 = data2.get(zhu.get(4)).get(0);
            w3 = data2.get(zhu.get(4)).get(1);
            if (N >= v1) {            // 计算b1
                b1 = dp(data1, data2, N - v1, m - 1) + v1 * w1;
            }
            if (N >= v1 + v2) {       // 计算b21,即购买主商品和附件1的最大满意度
                b21 = dp(data1, data2, N - v1 - v2, m - 1) + v1 * w1 + v2 * w2;
            }
            if (N >= v1 + v3) {       // 计算b22,即购买主商品和附件2的最大满意度
                b22 = dp(data1, data2, N - v1 - v3, m - 1) + v1 * w1 + v3 * w3;
            }
            if (N >= v1 + v2 + v3) { // 买的起主商品和附件1、附件2
                b3 = dp(data1, data2, N - v1 - v2 - v3, m - 1)
                        + v1 * w1 + v2 * w2 + v3 * w3;  // 计算b3,即购买主商品和附件1和附件2的最大满意度
                ret = Math.max(Math.max(Math.max(b0, b1), Math.max(b21, b22)), b3);
                dpFlag[N][m] = ret;
                return ret;
            } else if (N >= v1 + v2 || N >= v1 + v3) { // 买的起主商品以及(附件1或附件2)
                ret = Math.max(Math.max(b0, b1), Math.max(b21, b22));
                dpFlag[N][m] = ret;
                return ret;
            } else if (N >= v1) {   // 只买的起附件1
                ret = Math.max(b0, b1);
                dpFlag[N][m] = ret;
                return ret;
            } else {               // 都买不起
                dpFlag[N][m] = b0;
                return b0;
            }
        }
    }
}

#递归##动态规划求购物单问题##记录子问题解#
全部评论

相关推荐

我见java多妩媚:大外包
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务