当前位置:嗨网首页>书籍在线阅读

08-装箱问题

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

15.5 装箱问题

问题描述

19.png 有n个集装箱要装到两艘船上,每艘船的装载量分别为c1、c2,第i个集装箱可以承载的重量为wi,同时满足w1+w2+…+wn c1+c2。确定一个最佳的方案把这些集装箱装入这两艘船。

【分析】

首先将第一艘船尽量装满,再把剩下的集装箱装在第二艘船上。第一艘船尽量装满,等价于从n个集装箱中选取一个子集,使得该子集的总重量与第一艘船的装载量c1最接近,这样就类似于0/1背包问题。

问题解空间为(x1,x2,x3,…,xn)。其中,xi为0表示不装在第一艘船上,为1表示装在第一艘船上。

约束条件如下。

  • 可行性约束条件:w1x1+w2x2+…+wixi+…+wnxn
  • c1
  • 最优解约束条件:remain+cw>bestw(remain表示剩余集装箱重量,cw表示当前已装上的集装箱的重量,bestw表示当前的最优装载量)。

例如,集装箱的个数为4,重量分别是10t、20t、35t、40t,第一艘船的最大载重量是50t,则最优装载是将重量为10t和40t的集装箱装入。首先从第一个集装箱开始,将重量为10t的集装箱装入第一艘船,然后将重量为20t的集装箱装入,此时有10t+20t 50t。然后试探将重量为35t的集装箱装入,但是10t+20t+35t>50t,所以不能装入重量为35t的集装箱。紧接着试探装入重量为40t的集装箱,因为10t+20t+40t>50t,所以也不能装入。因此30t成为当前的最优装载量。

取出重量为20t的集装箱(回溯,重新调整问题的解),如果将重量为35t的集装箱装入第一艘船,因为10t+35t 50t,所以能够装入。因为45t>bestw,所以以45t作为当前最优装载量。

继续取出重量为35t的集装箱,如果将重量为40t的集装箱装入第一艘船,因为10t+40t 50t,所以装入第一艘船。因为50t>bestw,所以以50t作为当前最优装载量。

第15章\实例15-04.cpp
/********************************************
*实例说明:装箱问题
*********************************************/
1  #include<stdio.h>
2  #include<malloc.h>
3  int *w;                   /*存放每个集装箱的重量*/
4  int n;                    /*集装箱的数目*/
5  int c;                    /*第一艘船的装载量*/
6  int cw=0;                 /*当前装载量*/
7  int remain;               /*剩余装载量*/
8  int    *x;                /*存放搜索时每个集装箱是否选取*/
9  int bestw;                /*存放最优的放在第一艘船的重量*/
10 int    *bestx;            /*存放最优的集装箱装载方案*/
11 void Backtrace(int k)
12 {    
13     int i;
14     if(k>n)               /*递归的出口,如果找到一个解*/
15     {    
16         for(i=1;i<=n;i++) /*则将解存入bestx数组中*/
17            bestx[i]=x[i];    
18         bestw=cw;         /*记下当前的最优装载量*/
19         return;
20     }
21     else    
22     {    
23         remain-=w[k];
24         if (cw+w[k]<=c)             /*如果装入w[k],还小于或等于c*/
25         {    
26            x[k]=1;                  /*则装入w[k]*/
27            cw+=w[k];
28            Backtrace(k+1);    
                                       /*继续检查剩下的集装箱是否能装入*/
29            cw-=w[k];    /*不装入w[k]*/
30         }
31         if (remain+cw > bestw)    
                          /*如果剩余的集装箱不能完全装入*/
32         {    
33                x[k]=0;    
34                Backtrace(k+1);       /*继续从剩余的集装箱中检查是否能装入*/
35         }
36         remain+=w[k];       
37     }
38 }
39 int BestSoution(int *w,int n,int c)
40 /*搜索最优的装载方案:w存放每个集装箱的重量,
41 n表示集装箱数目,c表示第一艘船的装载量*/
42 {    
43     int i;
44     remain=0;                /*第一艘船剩下的装载量*/
45     for(i=1;i<=n;i++)    
46     {    
47         remain+=w[i];    
48     }
49     bestw=0;                
50     Backtrace(1);
51     return bestw;    
52 }
53 void main()
54 {
55     int i;
56     printf("请输入集装箱的数目:");
57     scanf("%d",&n);
58     w=(int*)malloc(sizeof(int)*(n+1));
59     x=(int*)malloc(sizeof(int)*(n+1));
60     bestx=(int*)malloc(sizeof(int)*(n+1));
61     printf("请输入第一艘船的装载量:");
62     scanf("%d",&c);
63     printf("请输入每个集装箱的重量\n");
64     for (i=1;i<=n;i++)    
65     {
66         printf("第%d个集装箱的重量:",i);
67         scanf("%d",&w[i]);    
68     }
69     bestw=BestSoution(w,n,c);
70     for (i=1;i<=n;i++)    
71     {    
72        printf("%4d",bestx[i]);    
73     }
74     printf("\n");
75     printf("存放在第一艘船上的集装箱的重量:%d\n",bestw);
76     free(w);
77     free(x);
78     free(bestx);
79 }

运行结果如图15.5所示。

396.png

图15.5 运行结果

【说明】

第14~20行是递归的出口,如果找到问题的一个解,则将解存入bestx数组中,并将cw记作当前的最优装载量。

第23行从剩余的集装箱中取出第k个集装箱(重量为w[k])。

第24行中,如果将第k个集装箱装入第一艘船上,总重量小于或等于c,则说明可以装入第一艘船。

第26~27行表示将第k个集装箱装入第一艘船上。

第28行继续检查剩下的集装箱,并选择合适的集装箱装入第一艘船。

第29行取出第k个集装箱,用来调整装入第一艘船的货物。

第31行中,如果剩余的集装箱不能完全装入第一艘船。

第33~34行表示不装入第k个集装箱,并检查剩余的集装箱是否能装入第一艘船。

第36行表示第k个集装箱重新成为待装入的集装箱。

第45~48行表示初始时将所有的集装箱都作为即将装入第一艘船的集装箱。

第49行初始化第一艘船的最优装载量。

第50行调用Backtrace函数从第1个集装箱开始试探装入第一艘船。