揹包問題是經典問題,網上已經提供了很多優秀的解法,這裡摘錄動態規則的方法,同時順便把揹包相關的變形問題也一些闡述。
問題:1. 經典揹包問題:給定乙個載重量為m,n個物品,其重量為wi,價值為vi,1<=i<=n,要求:把物品裝入揹包,並使包內物品價值最大。
2. 變形:要求裝入的物品重量最大?(問題很簡單,但請先別bs我)
3. 變形:要求裝入的物品重量剛好等於揹包的承重?換一種說法就是:n個數里挑出任意個數,使這些數的和等於某個值m。
4. 變形:n個數里挑出任意個數,使這些數的和最接近m,即和與m的差的絕對值最小。
問題1請參考:
核心思想如下:
在0/1揹包問題中,物體或者被裝入揹包,或者不被裝入揹包,只有兩種選擇。
迴圈變數i,j意義:前i個物品能夠裝入載重量為j的揹包中
(n+1)*(m+1)陣列value意義:value[i][j]表示前i個物品能裝入載重量為j的揹包中物品的最大價值
若w[i]>j,第i個物品不裝入揹包
否則,若w[i]<=j且第i個物品裝入揹包後的價值》value[i-1][j],則記錄當前最大價值(替換為第i個物品裝入揹包後的價值)
問題2:很簡單。可以將這裡的重量看成是問題1的價值。之所以寫出來是為了方便分析問題4.
問題3:採用類似於問題1的方法,對n個數(無序),以n[i]表示第i個數。構造乙個(n+1)行(m+1)列的矩陣(+1行與列是為了下標好計算)。
關鍵點:對於某個m=j。給定序列n[1~i],組成和為 j 的子集u中若包含n[i],則n[1~i-1]肯定能夠組成和為j-n[i]。
如圖所示,為了簡單起見,令n個數正好是1到n遞增(不需要是有序的,僅為舉例方便),令m=6。
矩陣的值v[i][j]有三種表示方法:
1. y。表示n[i] = j。這樣,由n[1~i]個數,和為j的一種挑法就是只挑出n[i]本身。
2. x。表示由n[1~i]個數構成和為j的集合中,任一集合都沒有n[i] 。
3. 矩陣的另乙個位址,表示n[i] 可以構成和為j的集合中的乙個元素,而其它的元素需要到矩陣的另乙個位址中繼續尋找。
演算法描述如下:
1. 若當前n[i]=j ,則v[i][j]標記為 「y」;
2. 判斷n[i]是否屬於加和集合。需要看n[1~i-1]是否可以構成 j-n[i]。判斷的方法就是對第j-n[i]列,從行號為i-1開始直到0,看是否有值不為 「x」。查詢的結果有兩種可能:
a. 沒有,即全為x。表示n[i]不可能屬於加和集合中的一分子,故把v[i][j]標記為 「x」;
b. 有。記錄轉轉位址。
當遍歷結束後。採用回溯可以得到所有構成的路徑。這時,標記為「y」的矩陣值即是路徑回溯的終點。n個數
\m 0
1 2
3 4
5 6
0 yx
x xx x
x 1x y
x x
x x
x 2
x x
y(1,
1)x
x x
3 x
x x
y(1,
1)(2
,2)(
2,3)
4 x
x x
x y(
1,1)
(2,2
)5 x
x xx x
y(1,1
)舉例分析:
初始化第0行與第0列。
看v[1][1],由於有n[1]=1,故標記為y。
看v[2][3],考慮n[2]=2是否是構成和為3的乙個元素,則需要看由元素集合n[1~i-1],是否可以構成j-n[i],即{1}是否可以構成和為1。從查詢v[1][1]找到v[0][1],發現v[1][1]標記為y,表示可以構成,所以v[2][3]記錄位址{1,1}。
看v[3][6],同理,若n[3]=3能構成和為6的乙個元素的話,就要求n[1~2]能構成和為3,查詢發現v[2][3]的值不是「x」,表示上述假設成立,因此記錄(2,3).
當遍歷結束後,回溯尋找和為m的方法,這裡m=6.
首先發現v[5][6],確定5,跳轉到v[1][1],為y,結束,集合為{1,5}. 同列往上繼續走到v[0][1],為x,結束。
往上走到v[4][6], 確定4,跳轉到v[2][2],為y,結束,集合為{2,4}. 同列往上繼續走到v[1][2]與v[0][2],皆為x,結束。
往上走到v[3][6],確定3,跳轉到v[2][3],確定2,跳轉到v[1][1],確定1,集合為{1,2,3}. 同列往上繼續走到v[0][1],為x; 回退,發現v[1][3]也為x,結束。
往上走到v[1~2][6],都沒有構成集合,結束。
這裡為什麼在找到一條路徑後,還需要繼續在同列往上走呢?這是為把所有組合都成找到,請自行分析m=7的情況,如果不往上走,將只能找到{2,5}與{3,4},而少一組{1,2,4}.而最後一組{1,2}又構成了3.
問題4:
運用問題2或3的解法可解。運用問題2來解比較快:假設揹包最大承重為m,解一次問題2,即可得到加和小於m,且最接近m的的值,設為s。由於求的是絕對值最小,所以有可能可以找到加和大於m的解,而這個解必然屬於揹包大小為m+1到m+(m-s)-1 範圍內,問題2的解。舉例如下:假設m=6,求得s=3,目前的絕對值差為3,而如果正確的解是s>m的情況,那麼該解必然屬於揹包大小為7到8當中的最優解。即,最壞情況下,給乙個大小為8的包,能裝滿,則這時和的絕對值差為2,比原來優,而揹包給的再大已經沒有意義。
01揹包問題 動態規劃求解
時間限制 1 sec 記憶體限制 128 mb 提交 48 解決 17 給定n種物品和乙個揹包,物品i的重量是wi,其價值為vi,問如何選擇裝入揹包的物品,使得裝入揹包的物品的總價值最大?在選擇裝入揹包的物品時,對每種物品i只能有兩種選擇,裝入或者不裝入,不能裝入多次,也不能部分裝入。第一行輸入物品...
0 1揹包問題,動態規劃求解
1.什麼是0 1揹包問題?有n個物品,它們有各自的體積和價值,現有給定容量的揹包,如何讓揹包裡裝入的物品具有最大的價值總和?舉例int v 每個物品對應的價值 int w 每個物品對應的重量 int bag 10 揹包最大承重10 0 1揹包問題 public static void main st...
用動態規劃求解0 1揹包問題
0 1揹包問題描述 有n件物品和乙個重量為m的揹包。每種物品均只有一件 第i件物品的重量是w i 價值是p i 求解將哪些物品裝入揹包可使價值總和最大。動態規劃的基本思想 將乙個問題分解為子問題遞迴求解,且將中間結果儲存以避免重複計算。通常用來求最優解,且最優解的區域性也是最優的。求解過程產生多個決...