1、問題
有n個集裝箱要裝上2艘載重量分別為c1和c2的輪船,其中集裝箱i的重量為wi,且∑wi <= c1 + c2。
問是否有一個合理的裝載方案,可將這n個集裝箱裝上這2艘輪船。如果有,找出一種裝載方案。
2、解析
c1和c2是相互獨立的,即如何在c1或者c2上,放置物品是互不干擾的。
但是假如先在c1上放置貨物,則因剩下的貨物不同,會使c2上裝載的貨物的情況發生變化。
因此,為了保證c1上裝載的情況,滿足c1和c2將所有的貨物都裝下,c1上應該盡可能的多放物品。
3、設計
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int num=100; 4 int n,c1,c2,w[num];// n個集裝箱,A,B貨輪載重量分別為C1,C2,W[i],第i個集裝箱的重量 5 int cw,bw,rw;//cw,當前集裝箱貨物重量;bw,最優載重重量,rw,剩余集裝箱重量; 6 int x[num],bx[num];//x[],A貨輪的當前結果;bx[],A貨輪的最優結果; 7 void BackTrack(int i) { 8 //處理完了前n個集裝箱; 9 if(i>n){ 10 if(cw>bw){//cw,目前A中裝了cw重量的集裝箱; 11 //更新最優解; 12 bw=cw; 13 for(int i=1;i<=n;i++) bx[i]=x[i]; 14 } 15 return; 16 } 17 //rw表示處理完第i個之后(選或不選),還剩下rw-w[i]重量的集裝箱未處理; 18 rw-=w[i]; 19 if(cw+w[i]<=c1){//cw,第i個貨箱之前的重量 + 第i個貨箱小於A的最大重量C1; 20 cw+=w[i];//加上 21 x[i]=1;//標記i被選 22 BackTrack(i+1); 23 cw-=w[i];//減去重量 24 x[i]=0;//撤銷標記; 25 } 26 //不選擇第i個物品的話; 27 //if cw:表示[1:i)的數據 rw:表示(i,n]的數據 ,不包括第i個的數據 28 //如果不包括第i的數據的和(cw+rw) 大於 目前最優解bw,則可以遞歸下去; 29 if(cw+rw > bw){ 30 x[i]=0; 31 BackTrack(i+1); 32 } 33 34 //處理完第i個物品當前的情況了; 35 //因為再上一層,有兩種情況; 36 //1;選擇第i物品; 37 //2:不選擇第i個物品 38 //如果目前處理的是上一層第1種情況,那么我們就有必要加上這個w[i]; 39 //否則會影響上一層處理第2種情況; 40 rw+=w[i]; 41 return ; 42 } 43 int main(){ 44 scanf("%d%d%d",&n,&c1,&c2); 45 for(int i=1;i<=n;i++) { 46 scanf("%d",&w[i]); 47 rw+=w[i];//rw表示目前最優集裝箱的剩余重量; 48 } 49 //遞歸回溯 50 BackTrack(1); 51 //bw表示A貨輪裝下的貨物重量;剩余的重量 > B可以放下的最多,則不可; 52 if(rw-bw>c2){ 53 printf("沒有裝載方案\n"); 54 }else{ 55 printf("貨輪A:\n"); 56 for(int i=1;i<=n;i++) { 57 if(bx[i]) { 58 printf("%d ",i); 59 } 60 } 61 printf("\n貨輪B:\n"); 62 for(int i=1;i<=n;i++) { 63 if(0==bx[i]) { 64 printf("%d ",i); 65 } 66 } 67 } 68 return 0; 69 }
4、分析
最壞情況要遍歷圖中所有結點,算法的時間復雜度為O(2")。因為,葉子結點有2",每個結點要計算機裝載量以判斷是否回溯。
5、源碼
https://github.com/ChenyuWu0705/Algorithm-Analyze-and-Design/blob/main/loan.cpp