有乙個容量為 n 的揹包,要用這個揹包裝下物品的價值最大,這些物品有兩個屬性:體積 w 和價值 v。
定義乙個二維陣列 dp 儲存最大價值,其中 dp[i][j] 表示前 i 件物品體積不超過 j 的情況下能達到的最大價值,每件物品只能被新增一次。設第 i 件物品體積為 w,價值為 v,根據第 i 件物品是否新增到揹包中,可以分兩種情況討論:
第 i 件物品可新增也可以不新增,取決於哪種情況下最大價值更大。因此,0-1 揹包的狀態轉移方程為:
// w 為揹包總體積
// n 為物品數量
// weights 陣列儲存 n 個物品的重量
// values 陣列儲存 n 個物品的價值
public int knapsack(int w, int n, int weights, int values) else }}
return dp[n][w];
}
空間優化在程式實現時可以對 0-1 揹包做優化。觀察狀態轉移方程可以知道,前 i 件物品的狀態僅與前 i-1 件物品的狀態有關,因此可以將 dp 定義為一維陣列,其中 dp[j] 既可以表示 dp[i-1][j] 也可以表示 dp[i][j]。此時:
因為 dp[j-w] 表示 dp[i-1][j-w],因此不能先求 dp[i][j-w],防止將 dp[i-1][j-w] 覆蓋。也就是說要先計算 dp[i][j] 再計算 dp[i][j-w],在程式實現時需要按倒序來迴圈求解。
public int knapsack(int w, int n, int weights, int values) }}
return dp[w];
}
有乙個容量為 n 的揹包,要用這個揹包裝下物品的價值最大,這些物品有兩個屬性:體積 w 和價值 v。
定義乙個二維陣列 dp 儲存最大價值,其中 dp[i][j] 表示前 i 件物品組合體積不超過 j 的情況下能達到的最大價值,每件物品都可以重複使用。設第 i 件物品體積為 w,價值為 v,根據第 i 件物品是否被使用,可以分兩種情況討論:
第 i 件物品可使用也可以不使用來進行組合,取決於哪種情況下最大價值更大。因此,0-1 揹包的狀態轉移方程為:
// w 為揹包總體積
// n 為物品數量
// weights 陣列儲存 n 個物品的重量
// values 陣列儲存 n 個物品的價值
public int knapsack(int w, int n, int weights, int values) else }}
return dp[n][w];
}
空間優化
第一行表示該單元沒有左邊,所以取上一行單元格的值;第二行表示該單元值的填寫只要看它的左邊的值。如果不理解,建議將二維dp**全部親手填一遍。
因此可以將 dp 定義為一維陣列,其中 dp[j] 既可以表示 dp[i-1][j] 也可以表示 dp[i][j]。此時:
public int knapsack(int w, int n, int weights, int values)
}return dp[w];
}
問題
狀態方程
優化空間後的狀態方程
區別0-1揹包
「0 - 1」揹包參考上一行,所以「0 - 1」揹包 倒序填表
完全揹包
「完全揹包」參考當前行,所以完全揹包正序填表
揹包問題(0 1揹包 完全揹包)
0 1揹包 有n件物品和乙個容量為v的揹包。第i件物品的費用是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。重要的點在於 每種物品僅有一件,可以選擇放 不放子問題 f i v 表示前i件物品恰好放入乙個 容量為v 的揹包可以獲得的最大價值。狀態轉移方程 遞推式 f i v max 考...
01 揹包問題和完全揹包
乙個旅行者有乙個最多能用m公斤的揹包,現在有n件物品,它們的重量分別是w1,w2,wn,它們的價值分別為c1,c2,cn.若每種物品只有一件求旅行者能獲得最大總價值。輸入的第一行為t,表示測試資料的組數。對於每組測試資料的第一行 兩個整數,m 揹包容量,m 200 和n 物品數量,n 30 第2.n...
01揹包和完全揹包問題
搞了好久終於來寫dp了 完全揹包問題和01揹包問題只有乙個區別,就是完全揹包中物品可以取無數次但01揹包只能取一次。而因此帶來的解法也只有乙個不同,那就是用滾動陣列時01揹包要從後向前列舉而完全揹包只需要從前往後列舉即可,具體為什麼這個問題屬實困惑了我一陣子。完全揹包從前向後列舉時前面的狀態可能已包...