問題描述:
一共有n個貨物要裝上兩艘重量分別為c1和c2的輪船上,其中貨物i的重量為Wi,且:
要求確定是否有一個合理的裝載方案可將貨物裝上這兩艘輪船。
采取策略:
(1)首先將第一艘輪船盡可能裝滿;
(2)將剩余的集裝箱裝上第二艘輪船。將第一艘輪船盡可能裝滿等價於選取全體集裝箱的一個子集,
使該子集中集裝箱重量之和最接近。由此可知,裝載問題等價於以下特殊的0-1背包問題:
算法設計:
先考慮裝載一艘輪船的情況,依次討論每個集裝箱的裝載情況,共分為兩種,要么裝(1),要么不裝(0),因此很明顯其解空間樹可以用子集樹來表示。
在算法Maxloading中,返回不超過c的最大子集和,但是並沒有給出到達這個最大子集和的相應子集,稍后完善。
在算法Maxloading中,調用遞歸函數Backtrack(1)實現回溯搜索。Backtrack(i)搜索子集樹中的第i層子樹。
在算法Backtrack中,當i>n時,算法搜索到葉結點,其相應的載重量為cw,如果cw>bestw,則表示當前解優於當前的最優解,此時應該更新bestw。
算法Backtrack動態地生成問題的解空間樹。在每個結點處算法花費O(1)時間。子集樹中結點個數為O(2^n),故Backtrack所需的時間為O(2^n)。另外Backtrack還需要額外的O(n)的遞歸棧空間。
代碼實現:

#include <iostream> using namespace std; typedef int* pINT; template<class Type> class Loading{ public: friend Type MaxLoading(Type* w,int num ,Type C1,int* bestx ); friend void SolveLoading(int C2,bool* x,int* w,int num); void Backtrack(int i); int num;/* 集裝箱數目 */ int * x;/* 當前解 */ int * bestx;/* 當前最優解 */ Type* w;/* 集裝箱重量數組 */ Type C1;/* 第一艘船的容量 */ Type cw; Type bestw; Type r;/* 剩余集裝箱重量 */ }; template<class Type> void Loading<Type>::Backtrack( int i ) { if( i > num){ if ( cw > bestw ) { for (int i = 1; i <= num ; i++ ) { bestx[i] = x[i]; bestw = cw; } } return ; } r -= w[i]; if ( cw+w[i] <= C1 ) { x[i] = 1; cw += w[i]; Backtrack(i+1); cw -= w[i]; } if ( cw+r > bestw ) { x[i] = 0; Backtrack(i+1); } r += w[i]; } template<class Type> Type MaxLoading( Type* w,int num ,Type C1,int* bestx ) { Loading<Type> X; X.x = new int[num+1]; X.w = w; X.C1= C1; X.num = num; X.bestx = bestx; X.bestw = 0; X.cw = 0; X.r = 0; for (int i = 1; i <= num ; i++ ) { X.r += w[i]; } X.Backtrack(1); delete[] X.x; return X.bestw; } template<class Type> void SolveLoading( int C2,int* x,Type* w,int num ) { int totalW = 0; int c1W = 0;/* 第一艘船總載重 */ for (int i = 1; i <= num ; i++ ) { if ( x[i] == 1 ) { c1W += w[i]; } totalW += w[i]; } if ( totalW-c1W > C2 ) { printf("沒有合理的裝載方案! :( "); return; } printf(" 裝載方案如下:\n "); printf(" 第一艘船裝 "); for (int i = 1; i <= num ; i++ ) { if ( x[i] == 1 ) { printf("%d ",i); } } printf("\n總載重 %d \n",c1W); printf(" 第二艘船裝 "); for (int i = 1; i <= num ; i++ ) { if ( ! x[i] ) { printf("%d ",i); } } printf("\n總載重 %d \n",totalW-c1W); } int main(int argc,char* argv[]){ int C1 = 0; int C2 = 0; int num = 0; int* x = NULL; int** m = NULL; int* w = NULL; printf("輸入第一艘船最大載重量:"); scanf("%d",&C1); printf("輸入第二艘船最大載重量:"); scanf("%d",&C2); printf("輸入貨物個數"); scanf("%d",&num); x = new int[num+1]; w = new int[num+1]; m = new pINT[num+1]; for (int i = 0; i < num+1 ; i++ ) { m[i] = new int[num+1]; } printf("分別輸入貨物重量(回車結束):\n"); for (int i = 1; i <= num ; i++ ) { scanf("%d",w+i); } MaxLoading( w, num, C1, x ); SolveLoading(C2, x, w, num); delete[] x; delete[] w; delete[] m; return 0; }
實現結果:
參考:王曉東《算法設計與分析》第二版