C 用遞迴演算法解決經典揹包問題

2022-09-26 05:48:12 字數 3027 閱讀 1701

1.引子

我們人類是一種貪婪的動物,如果給您乙個容量一定的揹包和一些大小不一的物品,裝到揹包裡面的物品就歸您,遇到這種好事大家一定不會錯過,用力塞不一定是最好的辦法,用腦子才行,下面就教您如何解決這樣的問題,以獲得更多的獎品。

2.應用場景

在乙個物品向量中找到乙個子集滿足條件如下 :

1)這個子集加起來的體積大小不能大於指定閥值

2)這個物品子集加起來價值大小是向量v中所有滿足條件1的子集中最大的

3.分析

揹包問題有好多版本,本文只研究0/1版本,即對乙個物體要麼選用,要麼就拋棄,不能將乙個物體再繼續細分的情況。這種問題最簡單的方法就是找出這個向量的所有子集,如同找出冪集中的子集一樣,但這種遍歷的方法恐怕並不會被聰明的我們所使用,現在舉辦這些活動的電視台也非常聰明,他們不但要求您能將物品裝進去,而且指定操作時間,這樣當您慢慢騰騰的裝進去倒出來的時候,時間恐怕早就到了,最終您可能一無所獲,這可不是我們希望的結果,我們需要使用一些策略:第一次我們可以從大小小於揹包容量的物品中隨意挑取乙個,這樣可以盡量爭取時間,選取第乙個後的每乙個我們希望其都是最優的,這樣能節省一定的時間。假設有這麼一組物品,其大小和價值如下表所示:

物品編號

大小價值12

1234

3434

56

程式設計客棧 56

8給我們乙個容量為12的揹包,讓我們裝上面這些物品,我們可以用下面的方法來解決尋找最優組合的問題

建立乙個二圍陣列,陣列包括n個行(n為物品數量)和capcity+1列

首先我們對第乙個物品進行取捨,因為物品1大小為2,先將物品1加入揹包,物品1的大小為2,則cap>=2的時候能容納item1,這時候揹包裡面物品的價值為item1.value=1,得到以下陣列01

2345

6789

1011120

0111

1111

1111

接下來處理物品1和物品2的子集,item2的大小為3,則只有cap=3的時候才能容納item2,當cap=3的時候講好能容納item2,此時揹包裡面價值item2.value=4,且剩餘空間為0,當cap=4的時候,能容納item2,且剩餘空間為1,不能容item1,當cap=5的時候,可以容納item1+item2,此時的價值為1+4 =5,得到第二行01

23www.cppcns.com45

vqsfdzlef 6

7程式設計客棧 8910

111200

1445

5555

55

5下面分析物品三,物品二,物品一的子集,物品三的大小為4,當cap=4的時候就能容納item3,但此時揹包裡面的價值為3,明顯小於上一行中的cap=4的價值(3<4),所以cap=4時不能將item3放進去,所以第三行的4位置應該和第二行的4位置一致,當cap=5的時候能夠容納item3,且剩餘空間為1,和cap=4情況一樣,拷貝上一行同一位置的值,當cap=6,放置item3後剩餘2,能容item1和item4,二者的總價值:1+3=4<5,故拷貝上一行同位置的值,cap=7的時候,能容item2+item3,總價值大小為7,5,故cap=8的時的值為7,cap=9的時候仍能容難item3+item2,value=7,cap=8的時候,能容納item1+item2+item3,且總價值大小為8,大於上一行同位置的值,故cap>=9時候,總價值大小為8,第三行:01

2345

6789

1011120

0144

5577

8888

按照這樣的邏輯可以得到下面兩列,最後二圍陣列是

0,0,1,1,1,1,1,1,1,1,1,1,1

0,0,1,4,4,5,5,5,5,5,5,5,5

0,0,1,4,4,5,5,7,7,8,8,8,8

0,0,1,4,4,6,6,7,10,10,11,11,13

0,0,1,4,4,6,8,8,10,12,12,14,14

得到這樣的陣列之後,我們需要作的是根據這個二圍陣列來產生最優物品子集,方法為

從第len行開始,比較最後一行cap索引位置的值是否大於上一行同一位置的值,如先比較第五行位置12的值(14)與第四行位置12的值(13),因為14!=13,所以item5放置到最優集合中,item5的大小為6,故比較第四行cap-6=6的位置上的值與上一行同一位置上值得大小,因為6!= 5,所以item4能放置到最優集合,下一步要比較的位置cap = 6-item4.size=6-5=1,第三行位置1與第二行位置1相同,故item3不能放置到最優集合,第二行和第一程式設計客棧行第乙個位置上的值也一樣,所以item2也不能放置進去,最後判斷item1是否應該在最優集合,item5+item4後,剩餘空間為1,不能容納item1,故最優集合為;

綜合上面的分析,我們可以得到這樣的乙個處理流程

1)首先建立乙個nx(cap+1)的二圍陣列

2)第一行從嘗試選擇第乙個物品開始

3)對於以後的行,對於每個容量1<=cap<=capacity,首先拷貝上一行同一位置的值下來,如果itemi.size<=cap並且上一行(cap-itemi.size)位置上的值與itemi.value的 和(tempmax)大於拷貝下來的值的話,就將拷貝下來的值替換為上一行(cap-itemi.size)位置上的值與itemi.value的 和(tempmax)

4)得到完整陣列之後,我們既可以根據陣列來確定最優集合了,首先從最後一樣最後位置開始,和上一行的同一位置進行比較,如果相同,則該行對應索引的物品不能放到揹包中,否則放到揹包,並且開始比較上一行與 上上一行在當前揹包剩餘空間索引出的值,如不等,則對應物品可放置,如此,直到處理到第二行和第一行的比對完成,然後根據當前揹包剩餘容量與第乙個物品的大小比對來確定物品一是否能放置到揹包中

4.源程式

5.結論

上文採用的是動態程式設計的方法來處理此類揹包問題,上面的文章中兄弟們也提到了用遞迴演算法時間複雜度的問題,認為遞迴演算法效率比較低下,這種疑問無可厚非,但遞迴演算法也有它的優點,很多問題都能用遞迴來解決,我目前學習的就是用這種演算法來解決一些常見問題,對於其他演算法,比如此問題也可以採用貪婪演算法,遺傳演算法等得以更好的解決,但本文暫不作討論,以後有時間,一定將這些演算法加以實現並詳細比較其優劣。

本文標題: c#用遞迴演算法解決經典揹包問題

本文位址:

用貪心演算法解決揹包問題

貪心演算法 顧名思義,貪心演算法 總是能做到當前看來是最好的選擇。也就是說貪心演算法並不從整體最優上加以考慮,它所作出的選擇只是在某種意義上的 區域性最優選擇 所謂貪心選擇性質是指所求問題的整體最優解可以通過一系列區域性最優的選擇,是貪心演算法與動態規劃演算法的主要區別。0 1揹包問題 給定n種物品...

0 1揹包問題(遞迴解決)

問題剖析 0 1揹包問題規定每個物品要麼選,要麼不選。因此可以設定物品選擇向量為y y1,y2,yn 那麼當yn 1時,y y1,y2,yn 1 必然為f n 1,c wn 的物品選擇向量,當yn 0時,必然為f n 1,c 的最優物品選擇向量。所以此時可以考慮動態規劃解法。得到根據上面的分析,我們...

遞迴法解決揹包問題

演算法思想 1 如果在某個時刻,選擇的資料項符合目標重量,那麼工作便完成了 2 從選擇的第乙個資料項開始,剩餘的資料量的加和必須符合揹包的目標量減去 第乙個資料項的重量,這是乙個新的目標重量 3 逐個嘗試組合剩餘資料項的可能性,但是注意不要嘗試所有的組合,因為只要資料項的和大於目標重量的時候,就會停...