0 1揹包問題(回溯結點類排序改進)

2021-07-28 02:32:00 字數 2432 閱讀 7483

/*

name: 0-1揹包問題

author: 巧若拙

date: 07-03-17 15:30

description:

給定n中物品和乙個容量為c的揹包,物品i的重量為wi,其價值為vi,

0-1揹包問題是如何選擇裝入揹包的物品(物品不可分割),使得裝入揹包的物品的價值為最大。

1.題目分析:

考慮到每種物品只有2種選擇,即裝入揹包或不裝入揹包,並且物品數和揹包容量已給定,

要計算裝入揹包物品的最大價值和最優裝入方案,可用回溯法搜尋子集樹的演算法進行求解。

2.演算法設計:

a. 物品有n種,揹包容量為tc,建立乙個物品類,分別用w和p儲存物品的重量和**,

設定物件陣列a[n]儲存各個物品的重量和**資訊,

設定物件c和best分別記錄揹包當前儲存物品的資訊,和已經獲得的最優解資訊,

x[i]標記第i種物品是否裝入揹包,用bestx[i]儲存第i種物品的最優裝載方案;

b. 用遞迴函式backtrace(t)來實現回溯法搜尋子集樹(形式引數t表示遞迴深度):

① 若t == n,則演算法搜尋到乙個葉結點,判斷當前總價值是否最優:

1> 若c.p>best.p,更新當前最優解(即best=c),更新裝載方案(即bestx[i]=x[i]( 0≤i < n));

② 對物品i裝與不裝兩種情況進行討論,先分析裝t號物品的情形,再分析不裝t號物品的情形,這樣回溯到上一層時,

x[t]再次歸零,同時c不包含a[t],以便討論完上層結點後,再次分析結點t。

if(c.w <= tc && c.p+sum(t) > best.p) backtrace(t+1);繼續進行裝載;

③ 若已測試完所有裝載方案,外層呼叫就全部結束。

c. 主函式呼叫一次backtrace(0)即可完成整個回溯搜尋過程,

最終得到的bestp和bestx[i]即為所求最大總價值和最優裝載方案。

在非遞迴回溯中,我們用x[t]的值表示是第幾次訪問結點t,剛開始x[t]==0,

如果t == n,表示t為葉子結點的子孫(即不存在t號物品),判斷已裝載的物品是否為最優解,然後直接回溯。

否則先分析裝t號物品的情形,並令x[t] = 1;c.w += a[t].w;c.p += a[t].p;

再分析不裝t號物品的情形,並令x[t] = 2;c.w += a[t].w;c.p += a[t].p;這樣cw和cp的值就已經還原了

兩種情況都分析完後x[t]==2,通過語句x[t--] = 0; 來卸掉t號貨櫃並回溯到上層結點。

利用sum(int t);計算結點t的子樹結點**之和時,原來的演算法是把所有子孫結點的**都累積起來,這樣會比實際值大,

因為很有可能某些子孫結點超載,根本不能裝進去,而我們也把它的**累積進來了。

乙個改進演算法是將物品按照單位**排好序,單位**高的靠前,這樣如果某個物品超載時,沒必要再累積其後面物品的**,

而是按照該物品的單位**乘以剩餘容量,這樣算出的總**雖然比實際裝載的總**略高些,但總比全部都加進去更接近真實值,

而且也減少了計算量(後面的物品就不用再計算了)。

本例給出了改進後的演算法

3. 複雜度分析:

因為裝載問題解空間的子集樹中葉子節點的數目為2^n,因而最壞情況下時間複雜度為o(2^n)。 */

#include#include#includeusing namespace std;

class goods

bool operator < (const goods &b)const //遞減序

friend int sum(int t);//結點t的子樹結點**之和

friend void backtrace(int t); //遞迴回溯

friend void backtrace_2(); //非遞迴回溯

int w, p; //分別儲存物品的重量,**

};const int n = 4; //物品的個數

int x[n]; //解向量

int bestx[n]; //最優解解向量

vectora;

goods c, best;//分別記錄揹包當前儲存物品的資訊和已經獲得的最優解資訊

int tc = 10; //揹包總容量

int main()

if (i < n) //說明到a[i]就超載了,後面的物品無需再分析,直接按照a[i]的單位**乘以剩餘容量計算總價值

s += int(r * a[i].p * 1.0 / a[i].w);

return s;

}void backtrace(int t) //遞迴回溯

}void backtrace_2() //非遞迴回溯,用x[t]的值表示是第幾次訪問結點t

else //表示 x[t] == 2,已經分析完畢,該回溯到上一層結點了

}}

回溯 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 種選擇,即裝入揹包或不裝入揹包,並且物品數和揹包容量已給定,要計算裝入揹包物品的最大...

0 1揹包問題(回溯)

描述 需對容量為c 的揹包進行裝載。從n 個物品中選取裝入揹包的物品,每件物品i 的重量為wi 價值為pi 對於可行的揹包裝載,揹包中物品的總重量不能超過揹包的容量,最佳裝載是指所裝入的物品價值最高。輸入多個測例,每個測例的輸入佔三行。第一行兩個整數 n n 10 和c,第二行n個整數分別是w1到w...