C語言演算法之揹包演算法

2021-06-18 13:58:08 字數 4560 閱讀 5698

0 / 1

揹包問題中,需對容量為

c 的揹包進行裝載。從

n 個物品中選取裝入揹包的物品,每件物品

i 的重量為

wi ,價值為

pi .

對於可行的揹包裝載,揹包中物品的總重量不能超過揹包的容量,最佳裝載是指所裝入的物品價值最高,即n ?

i=1pi xi 

取得最大值。約束條件為n ?

i =1wi xi≤c 和xi

?[ 0 

,1 ] 

(1≤i≤n)。

在這個表示式中,需求出

xt 的值。

xi = 1

表示物品

i 裝入揹包中,

xi =0 

表示物品

i 不裝入揹包。

0 / 1

揹包問題是乙個一般化的貨箱裝載問題,即每個貨箱所獲得的價值不同。貨箱裝載問題轉化為揹包問題的形式為:船作為揹包,貨箱作為可裝入揹包的物品。

例1-8 

在雜貨店比賽中你獲得了第一名,獎品是一車免費雜貨。店中有

n 種不同的貨物。規則規定從每種貨物中最多只能拿一件,車子的容量為

c,物品

i 需占用

wi 的空間,價值為

pi .

你的目標是使車中裝載的物品價值最大。當然,所裝貨物不能超過車的容量,且同一種物品不得拿走多件。這個問題可仿照

0 / 1揹包問題進行建模,其中車對應於揹包,貨物對應於物品。

0 / 1

揹包問題有好幾種貪婪策略,每個貪婪策略都採用多步過程來完成揹包的裝入。在每一步過程中利用貪婪準則選擇乙個物品裝入揹包。一種貪婪準則為:從剩餘的物品中,選出可以裝入揹包的價值最大的物品,利用這種規則,價值最大的物品首先被裝入(假設有足夠容量),然後是下乙個價值最大的物品,如此繼續下去。這種策略不能保證得到最優解。例如,考慮

n=2,

w=[100,10

,10]

,p =[20,15

,15]

,c = 1 0 5.

當利用價值貪婪準則時,獲得的解為

x= [ 1 ,0 

,0 ]

,這種方案的總價值為

2 0.

而最優解為

[ 0 ,1 

,1 ]

,其總價值為

3 0.

另一種方案是重量貪婪準則是:從剩下的物品中選擇可裝入揹包的重量最小的物品。雖然這種規則對於前面的例子能產生最優解,但在一般情況下則不一定能得到最優解。考慮

n= 2 

,w=[10

,20]

,p=[5

,100]

,c= 2 5.

當利用重量貪婪策略時,獲得的解為

x =[1,0]

,比最優解

[ 0 

,1 ]要差。

還可以利用另一方案,價值密度

pi /wi 

貪婪演算法,這種選擇準則為:從剩餘物品中選擇可裝入包的

pi /wi 

值最大的物品,這種策略也不能保證得到最優解。利用此策略試解

n= 3 

,w=[20,15

,15]

,p=[40,25

,25]

,c=30時的最優解。

我們不必因所考察的幾個貪婪演算法都不能保證得到最優解而沮喪,

0 / 1

揹包問題是乙個

n p-

複雜問題。對於這類問題,也許根本就不可能找到具有多項式時間的演算法。雖然按

pi /wi 

非遞(增)減的次序裝入物品不能保證得到最優解,但它是乙個直覺上近似的解。我們希望它是乙個好的啟發式演算法,且大多數時候能很好地接近最後演算法。在

6 0 0

個隨機產生的揹包問題中,用這種啟發式貪婪演算法來解有

2 3 9

題為最優解。有

5 8 3

個例子與最優解相差

1 0 %

,所有6 0 0

個答案與最優解之差全在

2 5 %

以內。該演算法能在o (

nl o gn

)時間內獲得如此好的效能。我們也許會問,是否存在乙個x (

x<1 0 0 

),使得貪婪啟發法的結果與最優值相差在

x%以內。答案是否定的。為說明這一點,考慮例子

n =2

,w = [ 1 ,y]

,p= [ 1 0 

,9y],和

c= y.

貪婪演算法結果為

x=[1,0]

,這種方案的值為

1 0.

對於y≥1 0 / 9

,最優解的值為

9 y.

因此,貪婪演算法的值與最優解的差對最優解的比例為(

(9y - 1 0

)/9y* 1 0 0 )%

,對於大的

y,這個值趨近於

1 0 0 %.

但是可以建立貪婪啟發式方法來提供解,使解的結果與最優解的值之差在最優值的

x% (

x<100

)之內。首先將最多

k 件物品放入揹包,如果這

k 件物品重量大於

c,則放棄它。否則,剩餘的容量用來考慮將剩餘物品按

pi /wi 

遞減的順序裝入。通過考慮由啟發法產生的解法中最多為

k件物品的所有可能的子集來得到最優解。

例13-9 

考慮n =4

,w=[2,4

,6,7]

,p=[6,10

,12,13]

,c = 11.

當k= 0

時,揹包按物品價值密度非遞減順序裝入,首先將物品

1放入揹包,然後是物品

2,揹包剩下的容量為

5個單元,剩下的物品沒有乙個合適的,因此解為

x = [ 1 ,1 

,0 ,0 ].

此解獲得的價值為

1 6.

現在考慮

k = 1

時的貪婪啟發法。最初的子集為 ,

, ,.子集 ,

產生與k= 0

時相同的結果,考慮子集

,置x3 為1.

此時還剩

5個單位的容量,按價值密度非遞增順序來考慮如何利用這

5個單位的容量。首先考慮物品

1,它適合,因此取

x1 為

1,這時僅剩下

3個單位容量了,且剩餘物品沒有能夠加入揹包中的物品。通過子集

開始求解得結果為

x = [ 1 ,0 

,1 ,0 ]

,獲得的價值為

1 8.

若從子集

開始,產生的解為

x = [ 1 ,0 

,0 ,1 ]

,獲得的價值為

1 9.

考慮子集大小為0和

1時獲得的最優解為

[ 1 ,0 

,0 ,1 ].

這個解是通過

k= 1的貪婪啟發式演算法得到的。

若k= 2

,除了考慮

k< 2

的子集,還必需考慮子集 ,

, ,,和.

首先從最後乙個子集開始,它是不可行的,故將其拋棄,剩下的子集經求解分別得到如下結果:

[ 1 ,1 

,0 ,0 ] 

,[ 1 ,0 

,1 ,0 ] 

,[ 1 ,0 

,0 ,1 ] 

,[ 0 ,1 

,1 ,0 ]

和[ 0 ,1 

,0 ,1 ]

,這些結果中最後乙個價值為

2 3,它的值比

k= 0

和k= 1

時獲得的解要高,這個答案即為啟發式方法產生的結果。

這種修改後的貪婪啟發方法稱為

k階優化方法(

k - o p t i m a l

)。也就是,若從答案中取出

k 件物品,並放入另外

k 件,獲得的結果不會比原來的好,而且用這種方式獲得的值在最優值的(

1 0 0 / 

(k + 1 ))

%以內。當

k= 1

時,保證最終結果在最佳值的

5 0 %

以內;當

k= 2

時,則在

3 3 . 3 3 %

以內等等,這種啟發式方法的執行時間隨

k的增大而增加,需要

測試的子集數目為

(nk 

),每乙個子集所需時間為o (

n),因此當

k >0

時總的時間開銷為o (

nk+1)。實際觀察到的效能要好得多。

演算法之揹包

不死族的巫妖王發工資拉,死亡騎士拿到一張n元的鈔票 記住,只有一張鈔票 為了防止自己在戰鬥中頻繁的死掉,他決定給自己買一些道具,於是他來到了地精商店前.死亡騎士 我要買道具 地精商人 我們這裡有三種道具,血瓶150塊乙個,魔法藥200塊乙個,無敵藥水350塊乙個.死亡騎士 好的,給我乙個血瓶.說完他...

經典演算法詳解 之 揹包演算法

揹包問題 knapsackproblem 是一種組合優化的 np完全問題 問題可以描述為 給定一組物品,每種物品都有自己的重量和 在限定的總重量內,我們如何選擇,才能使得物品的總 最高。這個問題涉及到了兩個條件 一是物品總的大小小於或等於揹包的大小,二是物品總的價值要盡量大。如果我們 用子問題定義狀...

經典演算法詳解 之 揹包演算法

揹包問題 knapsackproblem 是一種組合優化的 np完全問題 問題可以描述為 給定一組物品,每種物品都有自己的重量和 在限定的總重量內,我們如何選擇,才能使得物品的總 最高。這個問題涉及到了兩個條件 一是物品總的大小小於或等於揹包的大小,二是物品總的價值要盡量大。如果我們 用子問題定義狀...