问题描述:
一共有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
using namespace std;
typedef int* pINT;
template
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
void Loading::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
Type MaxLoading( Type* w,int num ,Type C1,int* bestx )
{
LoadingX;
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
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;
}
View Code
实现结果:
参考:王晓东《算法设计与分析》第二版