本文**
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...