1. 程式人生 > >【資料結構與演算法】回溯法解決裝載問題

【資料結構與演算法】回溯法解決裝載問題

回溯法解決裝載問題(約束函式優化)

解題思想

遍歷各元素,若cw+w[t]<=c(即船可以裝下),則進入左子樹,w[t]標記為1,再進行遞迴,若cw+r>bestw(即當前節點的右子樹包含最優解的可能),則進入右子樹,否則,則不遍歷右子樹。

完整程式碼實現如下

public class Loading {
	static int n;//貨箱數目
	static int[] w;//貨箱重量陣列
	static int c;//第一艘船的重量
	static int cw;//當前裝載的重量
	static int bestw;//目前最優裝載的重量
	static int r;
//剩餘貨箱的重量 static int[] x;//當前解,記錄從根至當前結點的路徑 static int[] bestx;//記錄當前最優解 public static int MaxLoading(int[] ww,int cc) { //初始化資料成員,陣列下標從1開始 n = ww.length - 1; w = ww; c = cc; cw = 0; bestw = 0; x = new int[n+1]; bestx = new int[n+1]; //初始化r,即剩餘最大重量 for(int i =1;i<=n;i++) { r +=
w[i]; } //計算最優載重量 backtrack(1); return bestw; } //核心演算法 public static void backtrack(int t) { //到達葉結點 if(t>n) { if(cw>bestw) { for(int i=1;i<=n;i++) { bestx[i] = x[i]; } bestw = cw; } return; } r -= w[t]; if(cw + w[t] <= c) {//搜尋左子樹 x[
t] = 1; cw += w[t]; backtrack(t+1); cw -= w[t];//回溯 } if(cw + r>bestw) { x[t] = 0;//搜尋右子樹 backtrack(t+1); } r += w[t];//恢復現場 } /* * 如果當前節點的右子樹不可能包含比當前最優解更好的解時,就不移動到右子樹上! 設bestw為當前最優解,Z為解空間樹的第i 層的一個節點 為剩餘貨箱的重量;當cw+r<=bestw時,沒有必要去搜索Z 的右子樹: 當前載重量cw+剩餘集裝箱的重量r>當前最優載重量bestw */ public static void main(String[] args) { // TODO Auto-generated method stub int[] ww = {0,20,30,60,40,40}; int c1 = 100; int c2 = 100; int n = ww.length - 1; MaxLoading(ww,c1); int weight2 = 0;//儲存第二艘船可能要裝的重量 for(int i=1;i<=n;i++) { weight2 += ww[i]*(1-bestx[i]);//bestx[i]的值只能為0或1 } if(weight2>c2) { System.out.println("無法載滿貨物"); } else { System.out.println("第一艘船裝載貨物的重量: " + bestw); System.out.println("第二艘船裝載貨物的重量: " + weight2); //第一艘船的裝載情況 for(int i = 1;i<=n;i++) { if(bestx[i] == 1) { System.out.println("第" + i + "件貨物裝入第一艘船"); } } //第二艘船的裝載情況 for(int i = 1;i<=n;i++) { if(bestx[i] == 0) { System.out.println("第" + i + "件貨物裝入第二艘船"); } } } } }