回溯演算法之最優裝載問題

2021-07-03 12:33:13 字數 2949 閱讀 9141

問題描述:有一批共n個貨櫃要裝上2艘載重量分別為c1和c2的輪船,其中貨櫃i的重量為wi,且

例如:當n=3,c1=c2=50,且w=[10,40,40]時,則可以將貨櫃1和2裝到第一艘輪船上,而將貨櫃3裝到第二艘輪船上;如果w=[20,40,40],則無法將這3個貨櫃都裝上輪船。

基本思路

: 容易證明,如果乙個給定裝載問題有解,則採用下面的策略可得到最優裝載方案。

(1)首先將第一艘輪船盡可能裝滿;

(2)將剩餘的貨櫃裝上第二艘輪船。

將第一艘輪船盡可能裝滿等價於選取全體貨櫃的乙個子集,使該子集中貨櫃重量之和最接近c1。由此可知,裝載問題等價於以下特殊的0-1揹包問題。

用回溯法設計解裝載問題的o(2^n)計算時間演算法。在某些情況下該演算法優於動態規劃演算法。

演算法設計:

用回溯法解裝載問題時,用子集樹表示其解空間顯然是最合適的。用可行性約束函式可剪去不滿足約束條件該約束函式去除不可行解,得到所有可行解)。

可以引入乙個上界函式,用於剪去不含最優解的子樹,從而改進演算法在平均情況下的執行效率。設z是解空間樹第i層上的當前擴充套件結點。cw是當前載重量;bestw是當前最優載重量;r是剩餘貨櫃的重量,即r=

演算法設計  

用回溯法解裝載問題時,用子集樹表示其解空間顯然是最合適的。可行性約束函式可剪去不滿足約束條件(

(w1x1+w2x2+...+wixi)<= c1)的子樹。在子集樹的第j+1層的節點z處,用cw記當前的裝載重量,即cw=(w1x1+w2x2+...+wjxj),當cw>c1時,以節點z為根的子樹中所有節點都不滿足約束條件,因而該子樹中解均為不可行解,故可將該子樹剪去。

下面的解裝載問題的回溯中,演算法maxloading返回不超過c的最大子集和,但並未給出達到這個最大子集和的相應子集。稍後加以完善。

演算法maxloading呼叫遞迴函式backtrack(1)實現回溯搜尋。backtrack(i)搜尋子集樹中第i層子樹。類loading的資料成語。記錄子集樹中結點資訊,以減少傳給backtrack的引數。cw記錄當前結點所相應的裝載重量,bestw記錄當前最大裝載重量。

在演算法backtrack中,當i>n時,演算法搜尋至葉節點,其相應的裝載重量為cw。如果cw>bestw,則表示當前解優於當前最優解,此時應更新bestw。

當i<=n時,當前擴充套件結點z是子集樹中的內部節點。該結點有x[i]=1和x[i]=0兩個兒子結點。其左兒子結點表示x[i]=1的情形,僅當cw+w[i] <=c時進入左子樹,對左子樹進行遞迴搜尋。其右兒子結點表示x[i]=0的情形。由於可行結點的右兒子結點總是可行的,故進入右子樹時不需要檢查可行性。

演算法backtrack動態地生成問題的解空間樹。在每個結點出演算法花費o(1)時間。子集樹種結點個數為o(2n),,故backtrack所需的計算時間o(2n)。另外backtrack還需要額外的o(n)的遞迴棧空間。

書上給出的演算法:

1.遞迴回溯:

template class loading;  

template void loading::backtrack(int i)

//搜尋子樹

if(cw+w[i]<=c)

backtrack(i+1);//x[i]=0;

}

template type maxloading(type w,type c,int n)

2.增加上界函式和構造最優解的改進

void backtrack (int i)

}r -= w[i];

if (cw + w[i] <= c) //搜尋左子樹

if (cw + r > bestw)

r += w[i];

}

進一步理解:

//再來學習一下回溯法

//一般解題步驟分為三步

//一:針對所給問題,定義問題的解空間

//二:確定易於搜尋的解空間結構(一般為子集樹或者排列樹)

//三:以深度優先的方式搜尋解空間,並且在搜尋過程中用減枝函式避免無效搜尋

//其中子集樹就是選一部分,比如0-1揹包問題,裝載問題,

//而排列樹就是選所有,只是順序不一樣,例如旅行商(郵遞員)問題

//下面是裝載問題的解法

//已知n個貨櫃,輪船載重量為c,貨櫃i的重量為wi,要求是在不超重的情況下,

//裝盡可能多數量的貨櫃

#define num 100

intn;  

//貨櫃數量

intc;  

//輪船載重量

intw[num]; 

//貨櫃重量

intx[num]; 

//當前搜尋的解向量

intr;  

//剩餘貨櫃重量

intcw; 

//當前輪船載重量

intbestw;  

//最優載重

intbestx[num]; 

//最優解向量

void

init()  

}  //形參代表搜尋第t層節點,從1開始

void

backtrack(

intt)  

bestw=cw;  

}  else

//判斷是否可以向右

//如果當前載重量加上剩餘貨櫃的重量沒有超過前乙個最優裝載量的話就不用考慮了

//此處即為剪枝函式

if(cw+r>bestw)        

r+=w[t];    //返回時還原剩餘貨櫃重量

}  }  

參考:

最優裝載問題回溯法 貪心選擇之最優裝載問題

有一批貨櫃要裝上一艘載重量為c的輪船。其中貨櫃i的重量為wi。最優裝載問題要求確定在裝載體積不受限制的情況下,將盡可能多的貨櫃裝上輪船。問題可以描述為 該問題可以用貪心演算法求解,要使用貪心演算法解決問題,我們必須先證明 1 該問題具備貪心選擇性質 2 該問題具備最優子結構性質.1 首先先證明貪心選...

回溯法 最優裝載問題

以簡單的語言說,就是給定兩艘船,要求一批貨物分別裝入。這道問題採用 先盡可能以最大載重裝一艘船,再以剩下的貨物裝另一艘 這樣,我們就將問題簡化為了0 1揹包問題。採用回溯法構建解空間,之後遍歷即可。思路很簡單,的注釋我也寫的很詳細了。def traceback depth global n,good...

裝載問題 回溯演算法

題目描述 有一批共n個貨櫃要裝上2艘載重量分別為c1和c2的輪船,其中貨櫃i的重量為wi。裝載問題要求確定,是否有乙個合理的裝載方案可將這n個貨櫃裝上這2艘輪船。如果有,找出一種裝載方案。題目出自 計算機演算法設計與分析 第三版 王曉東 這是乙個典型的回溯演算法問題。如下 template clas...