01揹包問題

2021-06-17 18:53:26 字數 3896 閱讀 6717

本文**

1.遞迴思想

0- 1 揹包問題如果採用遞迴演算法來描述則非常清楚明白, 它的演算法根本思想是假設用布林函式

knap( s, n) 表示n 件物品放入可容質量為s 的揹包中是否有解( 當knap 函式的值為真時

說明問題有解,其值為假時無解) . 我們可以通過輸入s 和n 的值, 根據它們的值可分為以下幾種情況討論:

( 1) 當s= 0時可知問題有解, 即函式knap( s, n) 的值為true; ( 2) 當s< 0 時這時不可能,

所以函式值為false; ( 3) 當輸入的s> 0 且n< 1 時即總物品的件數不足1, 這時函式值為false,

只有s> 0 且n \1 時才符合實際情況,這時又分為兩種情況: ( 1) 選擇的一組物體中不包括wn

則knap( s, n) 的解就是knap( s, n- 1) 的解. ( 2) 選擇的一組物體中包括wn 則knap( s, n) 的解

就是knap( s- wn, n- 1) 的解. 這樣一組wn 的值就是問題的最佳解. 這樣就將規模為n 的問題轉化為

規模為n- 1 的問題. 綜上所述0- 1 揹包問題的遞迴函式定義為:

knap( s, n) =∕true, s= 0

︳false, s< 0

︳false, s> 0 且n< 1

\knap( s, n- 1) 或knap( s- wn, n- 1) , s> 0 且n>= 1

採用此法求解0- 1 揹包問題的時間複雜度為o( n) . 上述演算法對於所有物品中的某幾件恰能裝滿揹包

時能準確求出最佳解. 但一般情況是對於某一些物品無論怎麼裝都不能裝滿揹包, 必須要按揹包的最大

容量來裝. 如物品件數為4, 其質量分別為: 10, 2, 5, 4, 揹包的容量為20, 則這四件物品無論怎麼放都不

能恰好裝滿揹包, 但應能最大限度裝, 即必須裝下10, 5, 4 這三件物品, 這樣就能得到最大質量19. 對於

這種裝不滿的揹包它的解決辦法是這樣的: 按所有物品的組合質量最大的方法裝揹包, 如果還裝不滿,

則我們可以考慮剩餘空間能否裝下所有物品中最小的那件, 如果連最小的都裝不下了則說明這樣得到

的解是最佳解, 問題解決. 這樣我們必須先找出所有n 件物品中質量最小的那件( 它的質量為min) , 但

是為了問題的解決我們不能增加運算次數太多, 並且必須運用上述遞迴函式. 那麼我們可通過修改s 的

值即揹包的容量, 從揹包容量s 中減去k( 它的值是從0 到min- 1 之間的乙個整數值) , 再呼叫遞迴函

數. 當k= 0 時即能裝滿揹包, 其它值也能保證揹包能最大限度裝滿, 這樣所有問題都解決了.

①例題一:

簡單揹包問題

time limit:   1000ms       memory limit:   65535kb 

submissions:   2217       accepted:   408

description 

設有乙個揹包可以放入的物品重量為s,現有n件物品,重量分別是w1,w2,w3,…wn。 

問能否從這n件物品中選擇若干件放入揹包中,使得放入的重量之和正好為s。 

如果有滿足條件的選擇,則此揹包有解,否則此揹包問題無解。

input輸入資料有多行,包括放入的物品重量為s,物品的件數n,以及每件物品的重量(輸入資料均為正整數)

多組測試資料。 

output對於每個測試例項,若滿足條件則輸出「yes」,若不滿足則輸出「no「 

sample input

20 5

1 3 5 7 9

sample output

yes

# include# includeint date[1005];

int f(int w,int s)

int main()

return 0;

}}

2.貪心演算法

用貪心法設計演算法的特點是一步一步地進行,根據某個優化測度(可能是目標函式,也可能不是目標函式),每一步上都要保證能獲得區域性最優解。

每一步只考慮乙個資料,它的選取應滿足區域性優化條件。若下乙個資料與部分最優解連在一起不再是可行解時,就不把該資料新增到部分解中,

直到把所有資料列舉完,或者不能再新增為止。

#include#includeusing namespace std;

struct good//表示物品的結構體

;good a[2000];

bool bigger(good a,good b)

int main()

sort(a,a+n,bigger);//呼叫sort排序函式,按照價值與重量比和質量排序貪心

s=0;//包內現存貨品的重量

value=0;//包內現存貨品總價值

for (i=0;i但仔細想就會發現有個很大的問題,

10 4

5 10

8 16

5 510 10

就會出問題,被裝進去就不會拿出來,可見「拿來主義」行不通!

接下來介紹另一種演算法:動規

3.動態規劃【正解】

用子問題定義狀態:即dp[i][v]表示前i件物品恰好放入容量為v的揹包可以獲得的最大價值。則其狀態轉移方程是:

dp[i][v]=max

對於以上的方程必須進行詳細的解釋下:「將前i件物品放入容量為v的揹包中」這個子問題,若只考慮第i件物品的策略(放或不放),那麼就可以轉化為乙個只牽扯前i-1件物品的問題。

第一種情況:如果第i件不放進去,那麼問題就轉化為「前i-1件物品放入容量為v的揹包中」,價值為dp[i-1][v];

第二種情況:如果放第i件物品,那麼問題就轉化為「前i-1件物品放入剩下的容量為v-weight[i]的揹包中」,此時能獲得的最大價值就是dp[i-1][v-weight[i]]再加上通過放入第i件物品獲得的價值value[i],及dp[i-1][v-weight[i]]+value[i];

最後再比較第一種與第二種所得的價值大小,哪種價值大,dp[i][v]的值就是哪種。

②例題二:採藥

time limit:   1000ms       memory limit:   65535kb 

submissions:   155       accepted:   50

description辰辰是個天資聰穎的孩子,他的夢想是成為世界上最偉大的醫師。為此,他想拜附近最有威望的醫師為師。醫師為了判斷他的資質,給他出了乙個難題。醫師把他帶到乙個到處都是草藥的山洞裡對他說:「孩子,這個山洞裡有一些不同的草藥,採每一株都需要一些時間,每一株也有它自身的價值。我會給你一段時間,在這段時間裡,你可以採到一些草藥。如果你是乙個聰明的孩子,你應該可以讓採到的草藥的總價值最大。」

如果你是辰辰,你能完成這個任務嗎?  

input輸入的第一行有兩個整數t(1 <= t <= 1000)和m(1 <= m <= 100),用乙個空格隔開,t代表總共能夠用來採藥的時間,m代表山洞裡的草藥的數目。接下來的m行每行包括兩個在1到100之間(包括1和100)的整數,分別表示採摘某株草藥的時間和這株草藥的價值。 

output輸出包括一行,這一行只包含乙個整數,表示在規定的時間內,可以採到的草藥的最大總價值。 

sample input

70 3

71 100

69 1

1 2sample output

3#include# include# define max(a,b) a>b?a:b

using namespace std;

int main()

cout

}

揹包問題 01揹包問題

n個物品,總體積是v,每個物品的體積的vi,每個物品的最大價值是wi,在不超過v的體積下求最大價值 eg揹包容積為 5 物品數量為 4 物品的體積分別為 物品的價值分別為 思路定義乙個二位陣列int f new int n 1 v 1 f i j 就表示在1 i個物品中選取體積小於v的情況的最大價值...

揹包問題 01揹包

有n件物品和乙個容量為v的揹包。第i件物品的重量是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。01揹包中的 01 就是一種物品只有1件,你可以選擇放進去揹包即1,也可以選擇不放入揹包中即0。include include using namespace std const int ...

揹包問題(01揹包)

1085 揹包問題 在n件物品取出若干件放在容量為w的揹包裡,每件物品的體積為w1,w2 wn wi為整數 與之相對應的價值為p1,p2 pn pi為整數 求揹包能夠容納的最大價值。input 第1行,2個整數,n和w中間用空格隔開。n為物品的數量,w為揹包的容量。1 n 100,1 w 10000...