題目描述
王強今天很開心,公司發給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
輸出
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 }
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++; }; } }