• 回溯法之装载问题


    问题描述:

        一共有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 <iostream>
    using namespace std;
     
    typedef int* pINT;
    template<class Type>
    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<class Type>
    void Loading<Type>::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<class Type>
     Type   MaxLoading( Type* w,int num ,Type C1,int* bestx )
    {
        Loading<Type> X;
        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<class Type>
     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(" 装载方案如下:
     ");
         printf(" 第一艘船装 ");
         for (int i = 1; i <= num ; i++ ) {
             if ( x[i] == 1 ) {
                 printf("%d ",i);
             } 
         }
         printf("
    总载重 %d 
    ",c1W);
     
     
         printf(" 第二艘船装 ");
         for (int i = 1; i <= num ; i++ ) {
             if ( ! x[i] ) {
                 printf("%d ",i);
             } 
         }
         printf("
    总载重 %d 
    ",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("分别输入货物重量(回车结束):
    ");
     
        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

    实现结果:

    参考:王晓东《算法设计与分析》第二版

              https://www.cnblogs.com/xymqx/p/3724356.html

  • 相关阅读:
    蘑菇街
    康拓展开
    CSS学习笔记
    专业名词
    专业名字
    01背包问题
    将bbr功能合入到centos7.3
    How to Identify User&Password of DataBase safely in SQL statement?
    tips for private constructor
    all Key Word of C#
  • 原文地址:https://www.cnblogs.com/cy0628/p/13998841.html
Copyright © 2020-2023  润新知