今天刷到一道有依賴的揹包問題,是牛客的華為機試題,記錄下解法。題目如下:
王強今天很開心,公司發給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 ] 。(其中 * 為乘號)
請你幫助王強設計乙個滿足要求的購物單。
顯然是一道有依賴的揹包問題,我們可以將其轉為分組揹包為題求解。
對於上述題目,a1,a2依賴於a,b1,b2,b3依賴於b,其中a,b稱為主件,a1,等為附件,若主件個數為n,我們可以將所有物品分為n個類別,每一類別是該主件與其附件的所有可能組合情況。例如對a類來說,我們將[a,(a,a1),(a,a1,a2),(a,a2)]歸為一類,類似這樣一共分成n個類別,就變成了分組揹包問題。
輸入資料,第一行為錢數,物件總數,以後各行分別為每件物品的**,重要程度,和依賴關係。0表示其為主件,其他數字表示其依賴於xx
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
這一段**是讀入上面的資料,將其處理成
last_imp=[[
0],[
0,1600
,3600
,5100
,3100],
[0,1200],
[0,1000]]
,last_price=[[
0],[
0,800,
1200
,1500
,1100],
[0,400],
[0,500]]
.last_imp可以看成是01揹包中的價值。last_price是01揹包中重量
也可以自己處理成想要的格式,我處理的比較亂還沒有整理。反正就是為了得到上面的格式。
每個前面加個0是為了空出下標為0的行和列。
n,cycle=
list
(map
(int
,input()
.split())
)price =[0
]*cycle
imp =[0
]*cycle
rely =[0
]*cycle
for i in
range
(cycle)
: price[i]
,imp[i]
,rely[i]
=list
(map
(int
,input()
.split())
)def
get_subset
(alist,primary)
: res =
[primary]
for i in
range
(len
(alist)):
for j in
range
(i,len
(alist)):
1]+primary)
return res
dependency =
dict()
for i in
range
(len
(rely)):
if rely[i]==0
: dependency[i+1]
=[]for i in
range
(len
(rely)):
if rely[i]!=0
: dependency[rely[i]]1
)last =
for k,v in dependency.items():
[k])
)v =
[price[i]
*imp[i]
for i in
range
(len
(imp))]
last_imp =[[
0]]last_price =[[
0]]flag =
for i in
range
(len
(last)):
imp_alist =[0
] price_alist =[0
]for j in
range
(len
(last[i]))
: imp_tmp =
0 price_tmp =
0for k in
range
(len
(last[i]
[j])):
imp_tmp +=v[last[i]
[j][k]-1
] price_tmp += price[last[i]
[j][k]-1
]
下面是根據上面的處理好的資料格式的**:就和01揹包一樣,在其基礎上加了個判斷,取每組的最大值。
def
group_pack
(last_imp,last_price,n)
: f =
for i in
range
(len
(last_price)):
[0for i in
range
(n+1)]
)for i in
range(1
,len
(last_price)):
for j in
range(1
,n+1):
max_value =
0for k in
range
(len
(last_price[i]))
:if j[k]:
tmp_val = f[i-1]
[j]else
: tmp_val = f[i-1]
[j-last_price[i]
[k]]
+ last_imp[i]
[k]if tmp_val >= max_value:
max_value = tmp_val
f[i]
[j]= max_value
return f[-1
][n]
華為機試 購物單 分組揹包
王強今天很開心,公司發給n元的年終獎。王強決定把年終獎用於購物,他把想買的物品分為兩類 主件與附件,附件是從屬於某個主件的,下表就是一些主件與附件的例子 主件附件 電腦印表機,掃瞄器 書櫃圖書 書桌檯燈,文具 工作椅無 如果要買歸類為附件的物品,必須先買該附件所屬的主件。每個主件可以有 0 個 1 ...
華為機試 購物單
輸入例子 1000 5 800 2 0 400 5 1 300 5 1 400 3 0 500 2 0 輸出例子 2200 解題思路 這是一道揹包問題。先考慮解決揹包問題,思路是這樣 比如說這道題目,給定總錢數n,共有m件商品可以購買,從這m件商品中選擇購買商品,使得購買商品的錢數不超過n,同時滿足...
華為機試 購物單
王強今天很開心,公司發給n元的年終獎。王強決定把年終獎用於購物,他把想買的物品分為兩類 主件與附件,附件是從屬於某個主件的,下表就是一些主件與附件的例子 主件附件 電腦印表機,掃瞄器 書櫃圖書 書桌檯燈,文具 工作椅無 如果要買歸類為附件的物品,必須先買該附件所屬的主件。每個主件可以有 0 個 1 ...