1. 程式人生 > >知識點:01揹包(多種姿勢:二維實現+一維實現+滾動陣列實現+揹包裝滿+輸出最優方案)

知識點:01揹包(多種姿勢:二維實現+一維實現+滾動陣列實現+揹包裝滿+輸出最優方案)

文章作者:Yx.Ac   文章來源:勇幸|Thinking (http://www.ahathinking.com)   轉載請註明,謝謝合作。

---

四月份還沒寫,不能這麼荒廢了呀,趕緊水一篇吧,哈哈。前些日子回顧了DP的一些基礎,就做一下整理吧,從0-1揹包開始。

本節回顧0-1揹包的基本模型,關於它的實現有很多種寫法,這裡對不同實現做個簡單列舉,主要是寫程式碼練手了,主要有以下幾方面內容:

==0-1揹包問題定義 & 基本實現

==0-1揹包使用滾動陣列壓縮空間

==0-1揹包使用一維陣列

==0-1揹包恰好背滿

==0-1揹包輸出最優方案

========================================

0-1揹包問題定義 & 基本實現

問題:有個容量為V大小的揹包,有很多不同重量weight[i](i=1..n)不同價值value[i](i=1..n)的物品,每種物品只有一個,想計算一下最多能放多少價值的貨物。

DP的關鍵也是難點是找到最優子結構和重疊子問題,進而找到狀態轉移方程,編碼就相對容易些。最優子結構保證每個狀態是最優的,重疊子問題也即n狀態的求法和n-1狀態的求法是一樣的;DP在實現上一般是根據狀態轉移方程自底向上的迭代求得最優解(也可以使用遞迴自頂向下求解)。

回到0-1揹包,每個物體i,對應著兩種狀態:放入&不放入揹包。揹包的最優解是在面對每個物體時選擇能夠最大化揹包價值的狀態。0-1揹包的狀態轉移方程為

1 f(i,v) = max{ f(i-1,v), f(i-1,v-c[i])+w[i] }

f(i,v)表示前i個物體面對容量為v時揹包的最大價值,c[i]代表物體i的cost(即重量),w[i]代表物體i的價值;如果第i個物體不放入揹包,則揹包的最大價值等於前i-1個物體面對容量v的最大價值;如果第i個物體選擇放入,則揹包的最大價值等於前i-1個物體面對容量v-cost[i]的最大價值加上物體i的價值w[i]。

對於實現,一般採用一個二維陣列(狀態轉移矩陣)dp[i][j]來記錄各個子問題的最優狀態,其中dp[i][j]表示前i個物體面對容量j揹包的最大價值。

下面給出0-1揹包的基本實現,時間複雜度為O(N*V),空間複雜度也為O(N*V),初始化的合法狀態很重要,對於第一個物體即f[0][j],如果容量j小於第一個物體(編號為0)的重量,則揹包的最大價值為0,如果容量j大於第一個物體的重量,則揹包最大價值便為該物體的價值。為了能單步驗證每個狀態的最優解,程式最後將狀態轉移矩陣的有效部分輸出到了檔案。

程式碼如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include <iostream> using namespace std; /* 0-1揹包 版本1 * Time Complexity  O(N*V) * Space Complexity O(N*V) * 設 V <= 200 N <= 10 * 狀態轉移方程:f(i,v) = max{ f(i-1,v), f(i-1,v-c[i])+w[i] } */ int maxValue[11][201]; /* 前i個物體面對容量j的最大價值,即子問題最優解 */ int weight[11]; int value[11]; int V, N; void main() {

相關推薦

知識點01揹包多種姿勢實現+實現+滾動陣列實現+揹包裝滿+輸出方案

文章作者:Yx.Ac   文章來源:勇幸|Thinking (http://www.ahathinking.com)   轉載請註明,謝謝合作。 --- 四月份還沒寫,不能這麼荒廢了呀,趕緊水一篇吧,哈哈。前些日子回顧了DP的一些基礎,就做一下整理吧,從0-1揹包開始。 本節回顧0-

筆試Java實現單例設計模式方案

public class SingletonTest { private SingletonTest() //建構函式私有化 {

js小數相加、相乘失去精度問題解析詳解方案

var CMX = CMX || {}; /** ** 加 **/ CMX.add = function (arg1, arg2) { var r1, r2, m, c; try { r1 = arg1.toString().split(".")[1].length; } catc

LVS模式四FULLNAT模式環境構造編譯核心

fullnat模式原理圖: FULLNAT模式原理: 1、client主機(cip)將請求發往前端的負載均衡器(vip),請求報文源地址是CIP,目標地址為VIP。負載均衡器收到報文後,發現請求的是在規則裡面存在的地址,那麼它將客戶端請求報文的源MAC地址改為自己DIP的MAC地址,目

ZOJ 3593 One Person GameExGcd + 題解

i++ 題解 mes tdi spa code game max include 思路:題意轉化為求 (ax+by=dis) || (ax+cy=dis) || (bx+cy=dis) 三個式子有解時的最小|x| + |y|。顯然求解特解x,y直接用擴展歐幾裏得,那麽怎麽求

牛客網《劍指Offer》 程式設計 25.複雜連結串列的複製 解法

題目描述 輸入一個複雜連結串列(每個節點中有節點值,以及兩個指標,一個指向下一個節點,另一個特殊指標指向任意一個節點),返回結果為複製後複雜連結串列的head。(注意,輸出結果中請不要返回引數中的節點引用,否則判題程式會直接返回空) 解題思路 這次使用時間複雜度為O(n

貪心演算法裝載

貪心演算法 貪心本質:一個貪心演算法總是作出當前最好的選擇,也就是說,它期望通過區域性最優選擇從而得到全域性最優的解決方案。 貪心演算法祕籍: (1)貪心策略 首先確定貪心策略,選擇當前看上去最好的一個方案。 (2)區域性最優解 根據貪心策略,一步一步地得到區域性最優解。 (3)全域

順序佇列求解迷宮

【問題描述】 以一個mXn的長方陣表示迷宮,0和1分別表示迷宮中的通路和障礙。設計一個程式,對任意設定的迷宮,求出一條從入口到出口的通路,或得出沒有通路的結論。 【任務要求】 實現佇列求解迷宮從入口到出口的最短通路。 【測試資料】 迷宮的測試資料如下:

淺析 AngularJS 全球化方案

本節是最後一節關於AngularJS的國際化和本地化方案討論,具體會和大家聊下目前有哪些第三方庫,以及優缺點。 首先談談國際化,AngularJS自帶國際化支援,提供了一些語言的國際化資原始檔檔案,具體的覆蓋面,大家可以去官網查詢。 下面聊聊怎麼使用這些資原始檔,一般來說

動態規劃演算法-----找零錢問題

動態規劃演算法通常用於求解具有某種最優性質的問題。動態規劃演算法與分治法類似,其基本思想都是將待求解問題分解成若干個子問題,先求解子問題,然後從這些子問題的解得到原問題的解。與分治法不同的是,適合於用動態規劃求解的問題,經分解得到的子問題往往不是互相獨立的。如果

城市交通網動態規劃,短路徑,輸出短路徑

【例9.5】城市交通路網 時間限制: 1000 ms         記憶體限制: 65536 KB  【題目描述】 下圖表示城市之間的交通路網,線段上的數字表示費用,單向通行由A->E。試用動態規劃的最優化原理求出A->E的最省費用。 如圖:求v1到v1

HDU 2612 BFS+取

1.題意:你約你喜歡的妹子去KFC,你們想找一家最近的,使得你和妹子到KFC所用時間和最短。 2.思路:相當於進行兩次BFS搜尋,可以從每個KFC當做起始點 出發搜尋Y和M,也可以從Y和M出發搜尋到達每個KFC的時間,然後用一個數組儲存到達每個kfc的總時間,找到最小值輸出

軟考之系統集成項目管理工程師包含2009-2018歷年真題詳解+第二版考試輔導教程+官方指定新版教程

工程 https follow 系統集成 分享圖片 get 項目管理 baidu 指定 軟考之系統集成項目管理工程師(包含2009-2018歷年真題以及答案詳解、系統集成項目管理工程師教程第2版-清華大學出版社-高清PDF,官方指定用書),持續更新後續年份的資料。請點贊!!

揹包問題 動態規劃 滾動陣列實現

比起別的講解揹包問題的部落格,這一篇更加註重在於理解如何用滾動陣列實現動態規劃。 揹包問題特徵 1.存在類似一個集合的求解所有子集的特性。關於一個集合的所有子集,會直接考慮每一個集合元素存在或不存在於子集中,最後對於一個由n個元素構成的集合,其子集數目是

限界分支法01揹包問題,優先順序佇列包含解的追蹤

前面提到: 不知道大家注意到沒有?上述實現方式沒有使用單位體積價值的排序,和之前提到01揹包回溯法基於單位體積價值實現不一樣(先裝單位體積價值高的)。 我們網上經常看到都是基於以上實現的,到底這個用有什麼好處了?實際上基於排序的單位體積價值是一個非常精確的限界函式 基於優先順序佇

限界分支法佇列方式追蹤解01揹包問題

追蹤解 追蹤解,上述實現的情況下,解都在最後一層,根本不知道之前的路徑是怎樣的,廣度優先搜尋,同一個緯度,假如不加指標判斷的話,根本不知道最優解是選擇的哪一個,所以需要同一個緯度的每一個結點,記住他之前的路徑,才能在最優解的時候之前是怎麼走過來的,每一個結點用一個數組記錄路徑,這樣實現的

回溯法深度優先剪枝和分支限界法寬度優先剪枝對比01揹包問題

限界函式: CurValue + rest <= BestValue 回溯法(深度優先)剪枝 # 遞迴方式 class pack_01_back_prune_test: def __init__(self,N,V,C,W): self

限界分支法實際上沒有剪枝,介紹的是廣度優先搜尋01揹包問題,佇列實現方式FIFO

限界分支法:佇列實現方式 前面已經介紹過限界分支法大部分是基於廣度優先搜尋,廣度優先搜尋一般藉助於佇列實現,剪枝的情況可以藉助於優先順序佇列。 實現如下: #%% class FIFO_01_Pack: def __init__(self,N,V,C,W):

hdu2546飯卡01揹包

http://acm.hdu.edu.cn/showproblem.php?pid=2546 Problem Description 電子科大本部食堂的飯卡有一種很詭異的設計,即在購買之前判斷餘額。如果購買一個商品之前,卡上的剩餘金額大於或等於5元,就一定可以購買成功(即使購買後卡上餘額

HDU 2546飯卡01揹包

飯卡 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 41634    Accepted Submission(