装载问题(回溯法)

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

posted @ 2021-05-17 16:39  programmer_w  阅读(1446)  评论(0编辑  收藏  举报