iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 14
0
自我挑戰組

學習筆記系列 第 19

0/1 Knapsack Problem 、Fractional Knapsack Problem

  • 分享至 

  • xImage
  •  

記錄學習內容。看網路上大大們的文章和影片,做些紀錄。
還不太了解,內容可能有錯誤。

教學來源(這3篇教學一起看,以下筆記和截圖來自這3篇教學):

用動態規劃解決問題:零壹背包問題(0/1 Knapsack Problem)

0/1 Knapsack Problem

4.5.1 0/1 Knapsack Problem (Program) - Dynamic Programming

筆記

1

背包問題,背包只能裝 重量 max_weight = 1000公克
現在有4個東西 :
A 1200元 , 200公克
B 1500元 , 500公克
C 1500 元 ,300公克
D 4000元 , 850公克
要在小於 背包裝的重量(1000公克之內) , 裝最大價值($$$$)

2

一開始想法會是 ,看每個東西的 1公克 值多少錢 ,然後錢錢 由大排到小 。
所以:
A 6元 , 1公克
B 3元 , 1公克
C 5 元 ,1公克
D 4.7元 , 1公克

先選A 在選 C ,在選 D ,在選B
200公克 + 300公克 + 850公克 + 500公克

但是 這邊是 0/1 Knapsack Problem 問題 ,0/1就是物品只能選或不選 。
所以 這樣 會不好判斷 ,如果選了 A、C 、D
200+ 300 +850 = 1350 > 背包重量1000

所以0/1問題不能用 Greedy approach ,這邊的解釋很清楚:

DAA - 0-1 Knapsack(截圖來自這篇教學)

如果背包重量60kg,給了ABC三樣東西 , 要在不超過背包重量的情況下 ,放東西到$$$最多。

如圖 , 價值 依序是 10 > 7 >6 , 所以 先選A ,在選B,在選C 。

選了A ,選了B 之後的價值會變成 100+280 =380$$$ 。重量會是10 +40=50
,所以就不能在選C了。所以最大$$$就會是380$$$

這樣就可以看出0/1問題 不能用Greedy approach了。
因為選B和C 價值更高!!!
B+C 的 價值 為 280+ 120 = 400 >380!!!
https://ithelp.ithome.com.tw/upload/images/20200914/20111994m2811lGWnm.png

3 繼續看0/1 問題 怎麼解決

https://ithelp.ithome.com.tw/upload/images/20200914/20111994JnLWXIEF2U.png
代表每個物品的價值:

int val[] = new int[] { 60, 100, 120 };

代表每個物品的重量:

int wt[] = new int[] { 10, 20, 30 };

背包重量:

int W = 50

https://ithelp.ithome.com.tw/upload/images/20200914/201119945qwCghbfZ1.png
如果 物品的重量 大於 背包重量 。跳過 。 到剩餘物品的背包問題(遞迴繼續)。

如果物品的重量 小於 背包重量 。
會有兩種情況 :
1 選擇這個物品到背包 : 所以 總價值會變成-- >這個物品的價值 + 剩餘物品的 背包問題(遞迴繼續) 。 然後總重量記的要扣掉該物品的重量。
2 不選擇這個物品 -- >剩餘物品的 背包問題(遞迴繼續)

這種 選 或 不選 的問題 通常長這樣 :
往左邊 是 不選這個物品 , 往右邊 是 選這個物品 。
然後這種問題的時間複雜度通常是O(2^n) ,簡單的記法 就是
1個func 生成 2個func 。
然後通常這種問題 ,都會重複計算 ,所以可以用動態規劃的方法。
https://ithelp.ithome.com.tw/upload/images/20200914/201119942CxJCDGzyE.png

選 或 不選 的問題 ,跟數學有關:
高一下數學2-3A觀念04係數性質的內涵
https://www.youtube.com/watch?v=ZJ1_bf3lheg&list=PLZruNYXiv2mB2VTi8erx5p9p1Z5mQHkR6&index=127&ab_channel=%E5%91%82%E5%86%A0%E7%B7%AF

接著來看,動態規劃的方式怎麼寫:

用了一個二維陣列 int [物品個數][ 總重量]
https://ithelp.ithome.com.tw/upload/images/20200914/20111994gDQKDKBflL.png

這邊有舉例 int [物品個數][ 總重量]
物品個數 就是 縱坐標 0 1 2 3 , 橫坐標是 重量 1 到 總重量 。
這邊只寫到6 ,先把它想成50kg這樣,應該比較好理解:
https://ithelp.ithome.com.tw/upload/images/20200914/20111994GFDppLYsD6.png

這邊 會變成 button –up ,一般迴圈的方法。
所以程式寫法 會是

int K[][] = new int[物品個數][ 背包總重量50kg];
For   0…物品個數 (i)
	For   0…背包總重量50kg (w)
		IF ( 物品重量 (10) <= w (10) )
			k[物品][w]  = MAX (val[物品] + K[物品- 1][w - wt[物品]] ,  K[物品-1][w] ) 
		 else  //如果物品重量 大於 現在重量 ,就不能放 ,所以價值維持上一個物品的
                   			K[i][w] = K[i - 1][w]; 

這邊的時間複雜度,就會是 物品個數 * 背包總重量
空間複雜度 ,就是二維陣列的size -- >物品個數 * 背包總重量

這個方法是 迴圈 和 陣列 。
或者也可以用recursion + memoization = DP(遞迴 和 陣列的方式)。教學文章裡有教,跳過。

這個看不太懂 :

int K[][] = new int[物品個數][ 背包總重量50kg];

每個K[][]的意思應該是 : 這個物品在這個重量下(放或不放)的最大價值

教學參考(截圖來自這部教學影片):
4.5.1 0/1 Knapsack Problem (Program) - Dynamic Programming
結果會類似這樣:
https://ithelp.ithome.com.tw/upload/images/20200914/20111994AD8835mNHP.png

那要怎麼知道最後選了哪些物品 ?

如果第ith 和[ith + 1] 物品 ,重量一樣,但是價值不一樣。代表ith 或[ith + 1] 某個物品有放到袋子裡 。

如果兩個東西價值不等於 ,代表有一個東西會放到袋子裡(看程式寫法,有些是i,有些是i+1)
如圖,大大的程式:
https://ithelp.ithome.com.tw/upload/images/20200914/201119947XhKbzXAzM.png

如圖:
8跟7 價值不同,所以代表有放4這個東西 ,扣掉4這個東西的重量和價值。
之後跑到3這個東西 ,繼續跟上一個物品比較:
https://ithelp.ithome.com.tw/upload/images/20200915/201119946rAnpmE20n.png

最後文章有講,可以把二維陣列換成一維陣列

,因為每一個物品 都是 跟 上一個物品 在比較 要不要放進袋子 。
所以可以只 存 上一個物品的 價值 ,也就是只需要一維陣列。

所以 背包問題 優化後的 時間複雜度是: 物品個數 * 背包總重量
空間複雜度是 : 背包總重量

Fractional Knapsack Problem

接著來看 Fractional Knapsack Problem 。

跟01問題不同的地方,就是物品可以是分數 。

Fractional Knapsack Problem | GeeksforGeeks
https://www.youtube.com/watch?v=m1p-eWxrt6g&ab_channel=GeeksforGeeks

Fractional Knapsack Problem
https://www.geeksforgeeks.org/fractional-knapsack-problem/

每一個物品 ,都先 價值 / 重量 。
就變成 1 單位的重量 ,價值多少 。
就 從 1 單位的重量 ,價值 最高的開始放到背包 。 如果那個物品的重量 大於 背包剩餘重量 。
那 就 只放 背包剩餘重量 的重量 。

像是 這個物品 重量30公斤 ,背包只剩下20公斤的重量 。
那 這個物品 可以只放20公斤 , 然後價值 就是原本的 2/3 倍 。

這個演算法的時間複雜度是 O(nlogn)

nlogn應該是指 把 每一個物品的 1單位重量的價值 排序的時間


上一篇
Java 、volatile
下一篇
NP, NP-Complete, NP-Hard問題
系列文
學習筆記46
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言