算法之装载问题

1. 问题描述:有一批共n个集装箱要装上2艘载重量分别为c1c2的轮船,其中集装箱i的重量为wi,且集装箱重量总和(w1+w2++wn<c1+c2。试找出一种合理的装载方案将这n个集装箱装上这2艘船。

2. 问题分析:如果该装载问题有解,装载策略为:

(1) 首先将第一艘船尽可能装满(等价于特殊的0-1背包问题,可采用动态规划算法);

(2) 然后将剩余的集装箱都装上第二艘轮船;

3. 解题思想:分析可知,使用子集树表示其解空间(在从n个元素的集合中找到满足条件的子集),剪枝函数:记录当前结点处已经到达的装载重量cw,若cw>c1,即以该结点为根的子树中所有结点都不满足条件,直接剪枝即可。

#include <iostream>
using namespace std;

int bestw=0;//当前最优载重量
int c=50;
int N=4;
int y[4];
int r;//剩余集装箱的重量

void Backtrack(int i,int cw,int w[],int x[])
{
    if(i>=N)//如果到达叶子结点
    {
        if(cw>bestw)
        {
            bestw=cw;
            for(int i=0;i<N;i++)
                y[i]=x[i];
        }
        return;
    }
    r-=w[i];
    //搜索子树
    if(cw+w[i]<=c)
    {
        x[i]=1;
        cw+=w[i];
        Backtrack(i+1,cw,w,x);
        cw-=w[i];
        x[i]=0;
    }
    if(cw+r>bestw)  //上界函数,保证到达叶结点时候的cw都优于当前的最优解bestw
    {
        x[i]=0;
        Backtrack(i+1,cw,w,x);
    }
    r+=w[i];
}


int main()
{
    int w[]={10,20,30,30};
    int x[N];
    for(int i=0;i<N;i++)
        r+=w[i];
    Backtrack(0,0,w,x);
    for(int i=0;i<N;i++)
        cout<<y[i]<<" ";
    cout<<endl;
    cout<<bestw<<endl;
}

分析可知,bestx可能被更新O(2^n)次,所以时间复杂性为O(n*2^n);

改进策略:首先只运行计算最优值的算法,计算出最优装载量bestw,此时需要O(2^n)时间,然后再运行Backtrack方法,将bestw值固定为已经计算出来的最优值,当首次到达叶子结点的时候终止算法,此时得到的x[]就是最优解。

猜你喜欢

转载自blog.csdn.net/qq_35503380/article/details/80430907