程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> c語言算法 - 貪婪算法 - 0/1背包問題

c語言算法 - 貪婪算法 - 0/1背包問題

編輯:關於C語言

在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時的貪婪啟發法。最初的子集為{1} , {2} , {3} , {4}。子集{1} , {2}產生與k=0時相同的結果,考慮子集{3},置x3 為1。此時還剩5個單位的容量,按價值密度非遞增順序來考慮如何利用這5個單位的容量。首先考慮物品1,它適合,因此取x1 為1,這時僅剩下3個單位容量了,且剩余物品沒有能夠加入背包中的物品。通過子集{3}開始求解得結果為x=[1 , 0 , 1 , 0],獲得的價值為1 8。若從子集{4}開始,產生的解為x=[1 , 0 , 0 , 1],獲得的價值為1 9。考慮子集大小為0和1時獲得的最優解為[1 , 0 , 0 , 1]。這個解是通過k=1的貪婪啟發式算法得到的。

若k=2,除了考慮k< 2的子集,還必需考慮子集{1 , 2} , {1 , 3} , {1 , 4} , {2 , 3} , {2 , 4}和{3 , 4}。首先從最後一個子集開始,它是不可行的,故將其拋棄,剩下的子集經求解分別得到如下結果:[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的增大而增加,需要測試的子集數目為O(nk),每一個子集所需時間為O(n),因此當k >0時總的時間開銷為O(nk+1)。實際觀察到的性能要好得多。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved