華為面試題:購物車問題(01揹包演算法升級)
問題描述
王強今天很開心,公司發給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.構建資料結構
建立物品物件Goods[價值v,權重p,物品的主附件id q,附件1,附件2]
構建Goods陣列儲存資料,將所有資訊匯入其中
利用Math.max(a,b)方法
在規定金額內,迴圈計算價值
程式碼邏輯
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
//輸入資訊
Scanner sc = new Scanner(System.in);
int money = sc.nextInt();
int n = sc.nextInt();
//校驗
if(n<=0||money<=0) System.out.println(0);
//存值
good[] Gs = new good[n+1];
for (int i = 1; i <= n; i++) {
int v = sc.nextInt();
int p = sc.nextInt();
int q = sc.nextInt();
Gs[i] = new good(v,p,q);
if(q>0){
if(Gs[q].a1==0){
Gs[q].setA1(i);
}else {
Gs[q].setA2(i);
}
}
}
//dp:記錄價值
int[][] dp = new int[n+1][money+1];
for (int i = 1; i <= n; i++) {
int v=0,v1=0,v2=0,v3=0,tempdp=0,tempdp1=0,tempdp2=0,tempdp3=0;
v = Gs[i].v;
tempdp = Gs[i].p*v; //只有主件
if(Gs[i].a1!=0){//主件加附件1
v1 = Gs[Gs[i].a1].v+v;
tempdp1 = tempdp + Gs[Gs[i].a1].v*Gs[Gs[i].a1].p;
}
if(Gs[i].a2!=0){//主件加附件2
v2 = Gs[Gs[i].a2].v+v;
tempdp2 = tempdp + Gs[Gs[i].a2].v*Gs[Gs[i].a2].p;
}
if(Gs[i].a1!=0&&Gs[i].a2!=0){//主件加附件1和附件2
v3 = Gs[Gs[i].a1].v+Gs[Gs[i].a2].v+v;
tempdp3 = tempdp + Gs[Gs[i].a1].v*Gs[Gs[i].a1].p + Gs[Gs[i].a2].v*Gs[Gs[i].a2].p;
}
/** 核心邏輯:計算金額
dp[i][j]為當前最大價值
i:第幾件商品
j:當前價值
*/
for(int j=1; j<=money; j++){
if(Gs[i].q > 0) { //當物品i是附件時,相當於跳過
dp[i][j] = dp[i-1][j];
} else {
dp[i][j] = dp[i-1][j];
if(j>=v&&v!=0) dp[i][j] = Math.max(dp[i][j],dp[i-1][j-v]+tempdp);
if(j>=v1&&v1!=0) dp[i][j] = Math.max(dp[i][j],dp[i-1][j-v1]+tempdp1);
if(j>=v2&&v2!=0) dp[i][j] = Math.max(dp[i][j],dp[i-1][j-v2]+tempdp2);
if(j>=v3&&v3!=0) dp[i][j] = Math.max(dp[i][j],dp[i-1][j-v3]+tempdp3);
}
}
}
System.out.println(dp[n][money]);
}
}
物品類
private static class good{
public int v; //物品的價格
public int p; //物品的重要度
public int q; //物品的主附件ID
public int a1=0; //附件1ID
public int a2=0; //附件2ID
public good(int v, int p, int q) {
this.v = v;
this.p = p;
this.q = q;
}
public void setA1(int a1) {
this.a1 = a1;
}
public void setA2(int a2) {
this.a2 = a2;
}
}
難點在於比較價值的邏輯上
第一層迴圈是將所有商品便利,第二層便利所有價格
迴圈比較同一件商品的價值和同價的商品誰的價值更大
選擇大的儲存在pd[i][j]中
相關文章
- 揹包問題(01揹包與完全揹包)
- 01揹包問題
- JavaScript中揹包問題(面試題)JavaScript面試題
- 01揹包面試題系列(一)面試題
- 位元組面試演算法題-0,1揹包問題面試演算法
- 揹包問題的演算法演算法
- 從【零錢兌換】問題看01揹包和完全揹包問題
- 揹包問題
- Facebook 面試題 | Backpack VI 揹包演算法面試題演算法
- 01揹包問題的解決
- 資料結構和演算法面試題系列—揹包問題總結資料結構演算法面試題
- 01揹包問題理解動態規劃演算法動態規劃演算法
- ACM 揹包問題ACM
- 【演算法】0-1揹包問題演算法
- 動態規劃 01揹包問題動態規劃
- 【動態規劃】01揹包問題動態規劃
- 動態規劃-01揹包問題動態規劃
- 動態規劃--01揹包問題動態規劃
- 揹包問題例題總結
- 揹包問題大合集
- acm演算法之三大揹包問題ACM演算法
- 【動態規劃】01揹包問題【續】動態規劃
- 揹包問題解題方法總結
- JavaScript 揹包問題詳解JavaScript
- 揹包問題的一道經典問題
- 揹包問題----動態規劃動態規劃
- 【動態規劃】揹包問題動態規劃
- Java實現-揹包問題IJava
- Java實現-揹包問題IIJava
- Java實現-揹包問題VIJava
- chapter12-2-揹包問題APT
- 二維費用揹包問題
- 程式碼隨想錄演算法訓練營第41天 | 01揹包問題 二維 、 01揹包問題 一維 、 416. 分割等和子集演算法
- 動態規劃系列之六01揹包問題動態規劃
- 程式碼隨想錄演算法訓練營第四十一天|01揹包問題, 01揹包問題—— 滾動陣列,分割等和子集演算法陣列
- 演算法——貪心演算法解0-1揹包問題演算法
- 揹包問題的遞迴與非遞迴演算法遞迴演算法
- 動態規劃-揹包01問題推理與實踐動態規劃