0-1揹包問題是子集選取問題。一般情況下,0-1揹包問題是np難得。0-1揹包問題的解空間可用子集樹 表示。在搜尋解空間的時,只要其左兒子節點是乙個可行節點,搜尋就進去其左子樹(約束條件)。當右子樹中可能包含最優解時才進入右子樹搜尋(限界函式)。否則就將右子樹剪去。
計算右子樹中解的上界的更好方法是將剩餘物品依其單位重量價值排序
,然後依次裝入物品,直至裝不下時,再裝入物品的一部分
而裝滿揹包。由此得到的價值是右子樹中解的上界
。
為了便於計算上界,可先將物品按照單位重量價值由大到小排序,此後,只要按照順序考察各個物品即可
。
在實現時,由bound計算當前結點處的上界。在解空間樹的當前擴充套件結點處,僅當要進入右子樹時才計算右子樹的上界bound
,以判斷是否將右子樹剪去。
進入左子樹時不需要計算上界
,因為其上界與其父節點上界相同。
計算每種物品單位重量的價值si=pi/wi
依貪心選擇策略,將盡可能多的單位重量價值最高的物品裝入揹包。
若將這種物品全部裝入揹包後,揹包內的物品總重量未超過c,則選擇單位重量價值次高的物品並盡可能多地裝入揹包。
依此策略一直地進行下去,直到揹包裝滿為止。
問題描述
假設有4個物品,物品的價值分別為p=[9, 10, 7, 4], 重量分別為w=[3, 5, 2, 1], 揹包容量c=9,使用回溯方法求解此0-1揹包問題,計算其最優值及最優解。要求畫出求得最優解的解空間樹, 給出具體求解過程。要求中間被剪掉的結點用×標記。
求解步驟
按照單位重量價值由大到小排好序,按照順序考查是否裝入物品
物品單位重量價值:[p1/w1, p2/w2, p3/w3, p4/w4] =(3, 2, 3.5, 4)
按照物品單位重量價值由大到小排序:
物品重量(w)
價值(v)
價值/重量(v/w)11
4422
73.533
9345
102上界計算
先裝入物品1,然後裝入物品2 和 3。裝入這三個物品後,剩餘的揹包容量為3,只能裝入物品4的3/5(2 * 3/5 = 1
)。 即上界為4+7+9+2*(9-6)=26
深度優先搜尋解空間樹,若左兒子是可行節點,才搜尋進入左子樹,否則將左子樹剪掉;若右子樹包含最優解,才搜尋右子樹,否則將右子樹剪掉。
以第乙個up=26為例,26=4+7+9+2*(9-6)打x的部分因為up值已經小於等於bestp了,所以沒必要繼續遞迴了。
;//物品數量 揹包容量 當前價值 當前重量 最優值 總重量 總價值
int n, c, cp, cw, bestp, total_w, total_p;
int x[100], best_x[100]; //記錄暫時選取狀態 記錄最優選取狀態
object o[100]; //儲存物品的陣列
void input()
}bool cmp(const object &a, const object &b)
void initilize()
//依照物品單位重量價值排序
sort(o + 1, o + n + 1, cmp);
//for(int i = 1; i <= n; ++i)
//cout << o[i].id << endl;
}//計算up值
int bound(int i)
//裝滿揹包
if(i <= n)
temp_cp += o[i].p / o[i].w * temp_cw;
return temp_cp;
}void backtrack(int i)
if(cw + o[i].w <= c)
//向右求解的約束條件
if(bound(i + 1) > bestp)
}void output()
{ cout輸入
請輸入物品個數和揹包容量:4 9
請輸入每個物品的價值和重量:
9 310 5
7 24 1
輸出
bestp = 23
選取的物品為 :
1 2 4
因為輸入的資料是沒有進行排序的,所以和例子中選取的1,3,4不同。但僅僅是順序不同,其實是一樣的。
將上面的例子排好序在進行測試
輸入
請輸入物品個數和揹包容量:4 9
請輸入每個物品的價值和重量:
4 17 2
9 310 5
輸出
bestp = 23
選取的物品為 :
回溯法 0 1揹包問題
0 1揹包問題 給定n種物品和一揹包.物品i的重量是wi,其價值為ui,揹包的容量為c.問如何選擇裝入揹包的物品,使得裝入揹包中物品的總價值最大?分析 0 1揹包是子集合選取問題,一般情況下0 1揹包是個np問題.第一步 確定解空間 裝入哪幾種物品 第二步 確定易於搜尋的解空間結構 可以用陣列p,w...
0 1揹包問題 回溯法
0 1揹包問題 回溯法 一 專案描述 每種物品只有2 種選擇,分別為 裝入揹包或不裝入揹包,物品數和揹包容量已給定,計算裝入揹包物品的最大價值和最優裝入方案,用回溯法搜尋子集樹的演算法進行求解。二 演算法設計 a.物品有n種,揹包容量為c,分別用p i 和w i 儲存第i種物品的價值和重量,用x i...
回溯法 0 1揹包問題
include include using namespace std class knap void knap backtrack int i 對第i個物品進行操作 return 如果沒有到葉子節點,就要對這個節點進行操作,即搜尋它的子樹,進入做左子樹表示可以選第i個,進入右子樹表示不能選第i個 ...