華為編程題:購物單問題


題目描述

王強今天很開心,公司發給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<Integer, List<Integer>> groups = new HashMap<>();
        for (int i = 1; i < m.length; i++) {
            if(m[i] == 0 ) {
                if(!groups.containsKey(i)) {
                    List<Integer> temp = new ArrayList<Integer>();
                    temp.add(i);
                    groups.put(i, temp);
                }
                
            }else {
                if (groups.containsKey(m[i])) {
                    List<Integer> list = groups.get(m[i]);
                    list.add(i);
                }else {
                    List<Integer> temp = new ArrayList<Integer>();
                    temp.add(m[i]);
                    temp.add(i);
                    groups.put(m[i], temp);
                }
            }
        }
        int index = 1;
        for(List<Integer> 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++;
        };
    }
    
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM