目錄
- 1.問題描述
1.1 問題描述
1.2 問題的數學表示(規劃類問題,此種表示可以轉換為回溯法)
1.3 三種方法的比較 - 2.動態規劃
2.1 刻畫一個最優解的結構特征(最優子結構)
2.2 遞歸地定義最優解的值(重疊子問題)
2.3 計算最優解的值,通常采用自底向上的方法
2.4 利用計算出的信息構造一個最優解 - 3.回溯法
3.1 01背包問題的數學描述
3.2 用回溯法搜索解空間
3.3 一個示例 - 4.分支限界法
4.1 分支限界法解決0-1背包問題
4.2 一個示例 - 5.可以轉換為0-1背包問題的雙核問題
5.1 題目描述
5.2 轉化為背包問題
1.問題描述
1.1 問題描述
假定n個商品重量分別為w0, w1, ..., wn-1,價值分別為p0, p1, ..., pn-1,背包載重量為M。怎樣選擇商品組合,使得價值最高?
1.2 問題的數學表示(規劃類問題,此種表示可以轉換為回溯法)
- 假設xi表示商品i被裝入背包的情況,xi = 0,1。根據題目要求,有如下約束方程和目標函數:
- 問題歸結為尋找一個滿足上述約束方程并使目標函數達到最大的解向量X = (x1, x2, ..., xn)。
1.3 三種方法的比較
- 動態規劃通過最優子結構,將問題轉換為子問題的求解。轉換的過程中,涉及到某個具體的商品是否選擇的問題。
- 回溯法根據數學表達式,搜索解向量(x1, x2, ..., xn)的整個解空間
搜索的時候利用貪心性質(按照單位重量價值遞減排序,估算可能的最高上界)、以及已經計算出的可行解作為界限進行剪枝。
但是回溯法,原則上要窮盡所有可能,只不過是對有些分支提前返回了。 - 分支限界法
剪枝方法同回溯法是一樣的:利用貪心性質(按照單位重量價值遞減排序,估算可能的最高上界)、以及已經計算出的可行解作為界限進行剪枝。
唯一的不同是,分支限界法利用的是優先隊列,并且,當針對一個結點進行擴展時,會將所有兒子結點進行展開,計算出所有兒子結點所能達到的最高上界。因此,當一個優先隊列中首結點是一個可行解,則結束。 - 因此,可以看出回溯法與分支限界法的本質不同是在于搜索解空間的遍歷方式不同。
回溯法是深度優先,要窮盡解空間的所有可能,找到最優解。
分支限界法是廣度優先,本質上也是窮盡了解空間的所有可能,找到最優解。
2.動態規劃
2.1 刻畫一個最優解的結構特征(最優子結構)
- 假設01背包問題的一個最優解為S,其中i為序號最大的商品;
那么S' = S - {i}必然是M - wi的最優解
證明方法可以采用cut-paste方法進行證明
2.2 遞歸地定義最優解的值(重疊子問題)
- 定義c[i, w]為商品1,....,i,最大重量為w的最優解(最大價值)。那么就有以下兩種情況:
- 如果wi > w,c[i, w]轉化為求解一個子問題c[i-1, w];
- 如果wi ≤ w,c[i, w]轉換成了求解兩個子問題:
一個包含商品i,pi + c[i-1, w- wi];
一個不包含商品i,c[i-1, w];
兩種情況中的較大者即為c[i, w] - (重疊子問題)很顯然c[i-1, w-wi]與c[i-1, w]有重疊子問題。
2.3 計算最優解的值,通常采用自底向上的方法
-
如下動態規劃方法的運行時間為Θ(nM)
動態規劃計算方法
2.4 利用計算出的信息構造一個最優解
- 如果c[i, w] = pi + c[i-1, w-wi],則i是答案的一部分;否則便不是。
3.回溯法
3.1 01背包問題的數學描述
- 假設xi表示商品i被裝入背包的情況,xi = 0,1。根據題目要求,有如下約束方程和目標函數:
- 問題歸結為尋找一個滿足上述約束方程并使目標函數達到最大的解向量X = (x1, x2, ..., xn )。
3.2 用回溯法搜索解空間
3.2.1 解空間
- 很顯然,解空間為一棵高度為n的完全二叉樹。所有解的可能性為所有的葉子節點,總共有2n種。
3.2.2 剪枝的方法(根據約束條件和bound來進行剪枝)
- 上界bound = 0
- 假定第i層左兒子表示商品i被裝入背包,右兒子表示未被裝入背包
- 將物體按照價值重量比的非增順序排序,然后按照這個順序搜索,在搜索過程中,盡量沿著左兒子繼續前進。
- 當不能沿著左兒子繼續前進時,得到問題的一個部分解,并把搜索轉移到右子樹。此時,估計由這個部分解所能得到的最大價值,把該值與當前的上界進行比較,如果高于上界,就繼續在右子樹上搜索,知道找到一個可行解,用可行解的值刷新上界bound。
- 向上回溯,尋找其他可行解。如果部分解所估計的最大值小于當前的上界,就丟棄當前正在搜索的部分解,直接向上回溯。
最大值的估算法(跟分支限界法本質上是一樣的)
- 假定當前解是{x0, x1, ..., xk-1 }
向上回溯的方法
- 如果當前的結點是左兒子分支結點,就轉而搜索相應的右兒子分支結點;
- 如果當前的結點是右兒子分支結點,就沿著右兒子分支結點向上回溯,知道左兒子分支結點為止,然后再轉而搜索相應的右兒子分支結點
3.2.3 回溯法的步驟描述
w_cur——表示當前正在搜索的部分解中轉入的總重量
p_cur——當前總價值
p_est——部分解可能達到的最大價值的估計值
p_total——當前搜索到的所有可行解中的最大價值,是當前目標函數的上界
yk、xk——部分解的第k個分量及其副本
k——表示當前搜索深度
- step1.按商品價值重量比的非增排序排序
- step2.w_cur、p_cur和p_total初始化為0,把部分解初始化為空,k=0
- step3.從當前的部分解可取得的最大價值p_est
- step4.若p_est > p_total,轉step5;否則,轉step8
- step5.從vk開始把商品裝入背包,直到沒有商品可裝貨裝不下vi為止,并生成部分解yk, ..., yi,k ≤ i < n,刷新p_cur
- step6.如果i ≥ n,得到一個新的可行解,把所有的yi復制給xi,p_total = p_cur,p_total是目標函數的新界;令k = n,轉step3,以便回溯搜索其他的可能解
- step7.否則,得到一個部分解,令k=i+1,舍棄商品vi,從商品vi+1繼續裝入,轉step3.
- (回溯)step8.當i ≥ 0且yi為0時,執行i = i -1,直到yi ≠ 0為止;即沿右兒子分支結點方向回溯,直到左兒子分支結點。
- step9.如果i < 0,算法結束,否則,轉step10
- step10.令yi = 0,w_cur = w_cur - wi, p_cur = p_cur - pi, k = i + 1,轉step3;從左兒子分支結點轉移到相應的右兒子分支結點,繼續搜索其他的部分解或可能解。
3.3 一個示例
M = 50
商品重量分別為5,15,25,27,30
商品價值分別為12,30,44,46,50
上面已經按照單位重量價值遞減順序排列。
4.分支限界法
4.1 分支限界法解決0-1背包問題
- 按價值重量比 遞減 的順序,對n個商品進行排序
排序后商品序號的結合為S = {0, 1, ..., n-1} - 將這些商品分為3個集合:
S1——選擇裝入背包的商品集合
S2——不選擇裝入背包的商品集合
S3——尚待選擇的商品集合 - S1(k)、S2(k)、S3(k)分別表示在搜索深度為k時的3個集合中的商品。開始時有:
S1(0) = ?
S2(0) = ?
S3(0) = {0, 1, ..., n-1}
4.1.1 分支方法(二叉分支)
- 假設比值pi/wi最大的商品序號為s(s ∈ S3),用s進行分支,一個分支結點表示把商品s裝入背包,另一個分支結點表示不把商品s裝入背包。
當商品按照價值重量比遞減排序后,s就是集合S3(k)中的第一個元素。特別地,當搜索深度為k時,商品s的序號就是集合S中的元素k。 -
把商品s裝入背包的分支結點
S1(k+1) = S1(k) ∪ {k}
S2(k+1) = S2(k)
S3(k+1) = S3(k) - {k} -
不把商品s裝入背包的分支結點
S1(k+1) = S1(k)
S2(k+1) = S2(k) ∪ {k}
S3(k+1) = S3(k) - {k}
4.1.2 上界估算方法(按照單位價值最大進行貪心選擇)
- 假定b(k)表示在搜索深度為k時,某個分支結點的背包中商品的價值上界。
此時S3(k) = {k, k+1, ..., n-1}。用如下方法計算兩種分支結點背包中商品價值的上界:
- 上述公式的理解
1)按照一個商品是否加入到S1集合,總共有2n個葉子節點,每個葉子節點對應一種情況
2)當一層一層向下搜索是,如果當前S1集合中的總重量超過了載重量M,則直接將b(k)置為0,該分支終止。
為什么這樣做?因為在搜索上一層時,該商品不應該加入到S1集合,這種不加入該商品情況對應于另一個分支。加入該商品的此分支已經不滿足要求了,所以剪枝。
4.1.3 分支限界法求解步驟
每個結點都包含如下信息:
??S1——當前選擇裝入背包的商品集合
??S2——當前不選擇裝入背包的商品集合
??S3——當前尚待選擇的商品集合
??k——搜索深度
??b——上界
bound——一個可行解的取值,當做剪枝的標準
- step1.bound = 0,把商品按價值重量比遞減排序
- step2.建立根節點X
X.b = 0
X.k = 0
X.S1 = ?
X.S2 = ?
X.S3 = S - step3. 若X.k == n,算法結束,X.S1即為裝入背包中的物體,X.b即為裝入背包中物體的最大價值;
否則轉向step4 - (分支1)step4.建立結點Y
Y.S1 = X.S1 ∪ {X.k}
Y.S2 = X.S2
Y.S3 = X.S3 - {X.k}
Y.k = X.k + 1
計算Y.b,將Y.b與bound進行比較,據此判定是否插入優先隊列;當S3為空時,找到一個可行解,判定是否更新bound。 - (分支2)step5.建立結點Z
Z.S1 = X.S1
Z.S2 = X.S2 ∪ {X.k}
Z.S3 = X.S3 - {X.k}
Z.k = Z.k + 1
計算Z.b,將Z.b與bound進行比較,據此判定是否插入優先隊列;當S3為空時,找到一個可行解,判定是否更新bound。 - step6.取出優先隊列首元素作為結點X,轉向step3
4.2 一個示例
-
有5個商品,重量分別為8,16,21,17,12,價值分別為8,14,16,11,7,背包的載重量為37,求裝入背包的商品及其價值。
5.可以轉換為0-1背包問題的雙核問題
5.1 題目描述
一種雙核CPU的兩個核能夠同時的處理任務,現在有n個已知數據量的任務需要交給CPU處理,假設已知CPU的每個核1秒可以處理1kb,每個核同時只能處理一項任務。n個任務可以按照任意順序放入CPU進行處理,現在需要設計一個方案讓CPU處理完這批任務所需的時間最少,求這個最小的時間
輸入描述:
輸入包括兩行: 第一行為整數n(1 ≤ n ≤ 50) 第二行為n個整數length[i](1024 ≤ length[i] ≤4194304),表示每個任務的長度為length[i]kb,每個數均為1024的倍數。
輸出描述:
輸出一個整數,表示最少需要處理的時間
輸入例子:
5 3072 3072 7168 3072 1024
輸出例子:
9216
5.2 轉化為背包問題
- 最小時間的意思即兩個核同時滿負荷運行,并且當兩個核所處理的任務量都接近于總任務量M的一半時,時間最少
- 因此題目轉換為:對于其中一個核,假設其任務量為上限M/2,在所有這些任務中選擇一個處理組合,使得這些任務組合在不超過M/2的情況下達到最大
- 因此本質上就是一個背包問題,背包的容量為M/2,商品的單位重量價值均為1,商品的重量即為任務所需要的時間量。