0-1揹包問題是子集選取問題。一般情況下,0-1揹包問題是np難的,0-1揹包問題的解空間可用子集樹表示。解0-1揹包問題的回溯法與解裝載問題的回溯法十分相似。
在搜尋解空間樹時,只要其左兒子結點是乙個可行結點,搜尋就進入其左子樹。當右子樹有可能包含最優解時才進入右子樹搜尋,否則將右子樹剪去。設r是當前剩餘物品價值總和:cp是當前價值;bestp是當前最優價值。當cp+r<=bestp時,可剪去右子樹。計算中解的上界的更好方法是剩餘物品依其單位重量價值排序,然後依次裝入物品,直到裝不下時,再裝入該物品的一部分而裝滿揹包。由此得到的價值是右子樹解的上界。
例如,對於0-1揹包問題的乙個例項,n=4,c=7,p=[9,10,7,4],w=[3,5,2,1].這個物品的單位重量價值分別為[3,2,3,5,4],以物品單位重量價值的遞減序裝入物品,先裝入物品4,然後裝入物品3和1,。裝入這3個物品後,剩餘的揹包容量為1,只能裝入0.2的物品2.由此得到乙個解為x = [1,0.2,1,1],其相應的價值為22.儘管這不是乙個可行解,但可以證明其價值是最優解的上界。因此,對於這個例項,最優值不超過22。
輸入:物品的數目n,揹包的容量c。各個物品的重量wi,各個物品的價值vi。
輸出:裝入揹包的最大價值。
執行結果:
為了便於計算上界,可先將物品依其單位重量價值從大到小排序,此後只要按順序考察各物品即可。在實現時,由bound計算當前結點處的上界。類knap的資料成員記錄解空間樹中的結點資訊,以減少引數傳遞及遞迴呼叫所需的棧空間。在解空間樹的當前擴充套件結點處。僅當要進入右子樹時才計算上界bound,以判斷是否可將右子樹剪去。進入左子樹時不需計算上界,因為其上界與其父結點的上界相同。
template class knap
;//計算以當前結點為根的子樹的價值上界
//計算上界的方法是將剩餘物品依其單位重量價值排序,然後依次裝入物品,直至裝不下時,再裝入該物品的一部分而裝滿揹包。
template typep knap::bound(int i)
if(i <= n) //裝滿揹包,剩餘的容量不足乙個,裝一部分
b += p[i]*cleft / w[i];
return b;
}//對解空間樹回溯搜尋,求得最大裝包價值
template void knap::backtrace(int i)
if(cw + w[i] <= c) //滿足約束函式,進入左子樹
if(bound(i+1) > bestp) //滿足限界函式,進入右子樹
backtrace(i+1);
}
//物品
class object
private:
int id; //物品標號
float d; //單位重量價值
};
template typep knapsack(typew *w, typep *p, typew c, int n)
if(w <= c) //能夠裝入所有物品
return p;
sort(q, q+n); //將n個物品依單位重量價值排序
knapk;
k.c = c;
k.n = n;
k.bestp = 0;
k.cw = 0;
k.cp = 0;
k.p = new typep[n+1];
k.w = new typew[n+1];
for(i = 1; i <= n; i++)
k.backtrace(1);
delete q;
delete k.p;
delete k.w;
return k.bestp; //返回最大裝包價值
}
2、演算法效率
計算上界需要o(n)時間,在最壞情況下有
回溯法解決0 1揹包問題 遞迴
include include include using namespace std typedef struct thing thing things const int goods 7 物品的數量 int max weigth 150 揹包承受的重量 int information 2 goo...
回溯 0 1揹包問題
回溯演算法的要點 1,針對所給問題,定義問題的解空間。2,確定容易搜尋的解空間的組織結構。3,通過剪枝優化搜尋過程。下面通過求解0 1揹包問題來分析使用回溯演算法的過程 1,根據問題的描述,設所有的物件數是n,對應的重量和價值分別為w 0 n 1 和v 0 n 1 於是這個問題就轉化成在這n件物件中...
回溯 01揹包問題
這裡再簡單寫一下問題要求 給定n中物品和乙個容量為c的揹包,物品i的重量為wi,其價值為vi,0 1揹包問題是如何選擇裝入揹包的物品 物品不可分割 使得裝入揹包的物品的價值為最大。1.題目分析 考慮到每種物品只有2 種選擇,即裝入揹包或不裝入揹包,並且物品數和揹包容量已給定,要計算裝入揹包物品的最大...