0-1揹包問題:物品總數n,每個物品的體積w[i],價值v[i],給定揹包的總容量w,求放入揹包中物品的最大價值。
用回溯法對0-1揹包問題進行求解,具體思路是:
1.使用解空間進行標記每個物品的放入情況,即要建立乙個陣列進行儲存其是否放入,可使用 bool x[i]進行標識;
2.回溯法第一感覺上是窮舉所有情況,但事實上,有好多種情況可以進行避免,即若第t個物品放入後(即x[t]=1)已經超出揹包重量,那麼,在x[t]=1情況下的t+1—n個物品就不用再考慮,這樣可以節省好多時間,回溯法有區別與窮舉法;
3.對於解空間,用解空間數進行組織資料,解空間樹的深度就是問題的規模n;
4.在解空間樹中,我們用左子樹、右子樹分別標記1/0情況,即左子樹的邊代表放入,右子樹的邊代表不放入;
5.建立回溯函式是重中之重,回溯函式建立分三步:
1(1)是否已經搜尋到了葉節點,若已經到了葉節點,此時該分支對應的價值情況與物品分配情況已經得知,為此進行儲存後返回,然後進行回溯;(2)若沒有搜尋到葉節點,那麼需要考慮對應物品是否可以放入揹包(涉及到問題的約束條件),若可以(在樹的左子樹進行操作),對當前價值、當前容量進行更新,x[t]=1進行標記已經放入揹包。接著進行下乙個物品的分析呼叫該回溯函式,若是回溯函式返回,則表明已經進行到葉節點,所有情況均考慮完成,那麼回溯正式開始。當前容量減去當前物品容量,當前價值減去當前物品價值,則表示當前物品沒有放入揹包的情況,後續執行第(3)步。(3)若對應的物品不能放入揹包,繼續分析後面剩餘物品的價值加上當前的價值是否會大於我們前面求得的最優價值,若後面剩餘物品的價值加上當前的價值小於,則我們就沒必要在進行往下考慮。否則,我們需要繼續往下考慮,即將當前的物品x[t]=0進行標記,接著對下乙個物品呼叫回溯函式。void backtrack(intt)2
7 best_v = now_v; //
記錄回溯中的最優價值
8return;9
}10if(now_w + w[t] <= w)
18if(bound(t+1) > best_v)
2223 }
用於記錄某次回溯情況
9bool best_x[n]; //
儲存最優回溯情況
10double now_v; //
當前價值
11double remain_v; //
剩餘價值
12double now_w; //
當前容量
13double best_v; //
最優價值
1415
double bound(int
k)16
22return remain_v +now_v;23}
2425
void backtrack(int
t)26
31 best_v = now_v; //
記錄回溯中的最優價值
32return;33
}34if(now_w + w[t] <= w)
42if(bound(t+1) > best_v)
4647}48
49void knapsack(double w, int
n)50
58if(sum_w <=w)
64 backtrack(1
);65 cout << "
the best value is:
"<< best_v <
66 cout << "
the condiction of these goods are:
"<
67for(int i = 1; i <= n; i ++)71}
7273
intmain()
7482
knapsack(w,n);
83return0;
84 }
注: **來自陳小玉老師《趣學演算法》
回溯法求解01揹包問題
在前面文章我們使用動態規劃求解了揹包問題,時間複雜度是o cn 當我們的c的值非常大的時候,說消耗的時間也是非常大的!接下來我們就使用回溯法來求解這個問題,其時間複雜度為o n2n 這個結果當我們的c的值是小於2n 的時候,該演算法所需的時間是小於動態規劃的!既然使用了回溯法,我們就的構造解析樹,因...
回溯法求解0 1揹包問題
include using namespace std struct dot void getvalue int weight,int value void calculate int weight,int value else while deep 6 else int main 選擇第1個 當前...
演算法實驗 回溯法求解0 1揹包問題
通過剪枝和衝突,走遍所有可能的選擇,最終得到最優解 1 每個節點有兩種選擇方法,依次對所有可能的方法進行遍歷 2 在遍歷的過程中通過設定一全域性變數用來比較所有的解法的結果,最終得到最優解 lagestv 0bestx 1 2 def jianzhi i,n,c,w,ww if i n return...