华为编程题:购物单问题

题目描述

王强今天很开心,公司发给N元的年终奖。王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:

 

主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅

 

如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。王强想买的东西很多,为了不超出预算,他把每件物品规定了一个重要度,分为 5 等:用整数 1 ~ 5 表示,第 5 等最重要。他还从因特网上查到了每件物品的价格(都是 10 元的整数倍)。他希望在不超过 N 元(可以等于 N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
    设第 j 件物品的价格为 v[j] ,重要度为 w[j] ,共选中了 k 件物品,编号依次为 j 1 , j 2 ,……, j k ,则所求的总和为:
v[j 1 ]*w[j 1 ]+v[j 2 ]*w[j 2 ]+ … +v[j k ]*w[j k ] 。(其中 * 为乘号)
    请你帮助王强设计一个满足要求的购物单。

 

 

输入描述:

输入的第 1 行,为两个正整数,用一个空格隔开:N m

(其中 N ( <32000 )表示总钱数, m ( <60 )为希望购买物品的个数。)

 

从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v p q

 

(其中 v 表示该物品的价格( v<10000 ), p 表示该物品的重要度( 1 ~ 5 ), q 表示该物品是主件还是附件。如果 q=0 ,表示该物品为主件,如果 q>0 ,表示该物品为附件, q 是所属主件的编号)

 

 

输出描述:

 输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值( <200000 )。
示例1

输入

复制
1000 5 800 2 0 400 5 1 300 5 1 400 3 0 500 2 0

输出

2200
 

思路:为背包问题的拓展问题:使用动态规划算法,先对物品进行分组(附件和对应主件放在一组,没有附件的单独一组),然后转化为分组的背包问题。



分组的背包问题:
6 分组的背包问题
6.1 问题
  有 N 件物品和一个容量为 V 的背包。第 i 件物品的费用是 C i ,价值是 W i 。这些物品被划分为 K 组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
6.2 算法
  这个问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选。也就是说设 F[k,v] 表示前 k 组物品花费费用 v 能取得的最大权值,则有:
    F[k,v] = max{F[k − 1,v],F[k − 1,v − C i ] + W i | item i ∈ group k}
  使用一维数组的伪代码如下:
    for k ← 1 to K
      for v ← V to 0
        for all item i in group k
          F[v] ← max{F[v],F[v − C i ] + W i }

 

本题如何如何转化为“分组的背包问题”:这个问题关键是如何将本题中的组(主件和附件组成的组)转换为“分组的背包问题”中的组,“分组的背包问题”中的组在选择的时候只能从中选择一件。转化方法是将本题中组元素组合成单独可选的,比如本题有组 A,元素为[x,y], 其中y是x的附件。选择y必须选择x. 在进行选择时,要么只选x, 要么选择x 和y. 所以可以转换为“分组的背包问题”中的组[x, [x, y]]. 这样就实现了组的转化,转化完即可按照“分组的背包问题”思路解决:
 
代码如下:
package com.huawei;
import java.util.Scanner;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Demo{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();
        int n = sc.nextInt();
        int[] v = new int[n+1];
        int[] p = new int[n+1];
        int[] q = new int[n+1];
        int groups = 0;
        for(int i = 1; i<=n; i++){
            v[i] = sc.nextInt();
            p[i] = sc.nextInt();
            q[i] = sc.nextInt();
            if(q[i] == 0) {
                groups++;
            }
        }
        
        //分组
        int[][] _v = new int[groups +1][4];
        int[][] _p = new int[groups +1][4];
        processData(q, v, p, _v, _p);
        
        int gc = _v.length;
        int[][] r = new int[gc][m+1];
        for(int i = 1; i< gc; i++){
            for(int j = 1; j<= m; j++){
                
                int max = r[i-1][j];
                for (int t = 1; t < _v[i].length; t++) {
                    int tempv = _v[i][t];
                    int tempp = _p[i][t];
                    if(tempv != 0 && tempv <= j) {
                        max = Math.max(max, r[i - 1][j - tempv] + tempp);
                    }
                }
                r[i][j] = max;
            }
        }
        System.out.println(r[gc -1][m]);
    }
    
    private static void processData(int[] m, int[] v, int[] p, int[][] _v, int[][] _p) {
        Map> groups = new HashMap<>();
        for (int i = 1; i < m.length; i++) {
            if(m[i] == 0 ) {
                if(!groups.containsKey(i)) {
                    List temp = new ArrayList();
                    temp.add(i);
                    groups.put(i, temp);
                }
                
            }else {
                if (groups.containsKey(m[i])) {
                    List list = groups.get(m[i]);
                    list.add(i);
                }else {
                    List temp = new ArrayList();
                    temp.add(m[i]);
                    temp.add(i);
                    groups.put(m[i], temp);
                }
            }
        }
        int index = 1;
        for(List list : groups.values()) {
            int size = list.size();
            if(size == 1) {
                _v[index][1] = v[list.get(0)];
                _p[index][1] = p[list.get(0)] * v[list.get(0)];
            }else if (size == 2) {
                _v[index][1] = v[list.get(0)];
                _p[index][1] = p[list.get(0)] * v[list.get(0)];
                
                _v[index][2] = v[list.get(0)] + v[list.get(1)];
                _p[index][2] = p[list.get(0)] * v[list.get(0)] + p[list.get(1)] * v[list.get(1)];
            }else {
                _v[index][1] = v[list.get(0)];
                _p[index][1] = p[list.get(0)]* v[list.get(0)];
                
                _v[index][2] = v[list.get(0)] + v[list.get(1)];
                _p[index][2] = p[list.get(0)] * v[list.get(0)] + p[list.get(1)] * v[list.get(1)];
                
                _v[index][3] = v[list.get(0)] + v[list.get(1)] + v[list.get(2)];
                _p[index][3] = p[list.get(0)] * v[list.get(0)]  + p[list.get(1)]* v[list.get(1)] + p[list.get(2)]* v[list.get(2)];
            }
            index++;
        };
    }
    
}

 

你可能感兴趣的:(华为编程题:购物单问题)