回溯法--装载问题:递归调用且添加返回值,通过返回值将时间从o(n*2^n)减小到(2^n)

#简介:
两个船要装一些货物,我们想知道是否有一种方式可以将货物全部装下。
网上的代码都是以算法与程序设计为基本,但是没有做出最后一步优化:递归返回保存路径

#这里提供一种有返回值的递归,充分利用递归来减小复杂度,使复杂度尽可能达到o(2^n),而且不像其他代码一样需要一个中间数组X[n]来保存当前路径,这个算法不需要,可以节省空间

#直接上代码,具体如下

    #include <iostream>
    #include <string.h>
    #define YES 1       //这个可以
    #define NO 0        //这个不行
    #define RETURNBACK 2        //这个一定是!!!

    using namespace std;

    class Loading
    {
    public:
        int MaxLoading(int*,int,int,int,int*);       //初始化函数
    private:
        int Backtrack(int);    //递归函数求解
        int n;                  //箱子总数
        int* w;                 //箱子重量数组
        int c;                  //船的重量
        int cw;                 //已装重量
        int* bestx;             //最佳箱子装载方式
        int bestw;              //最佳重量
        int r;                  //船剩余重量
    };

    int Loading::Backtrack(int i)
    {
        /*当到达最后一个节点时*/
        if(i == n-1)
        {
            cw += w[i];
            if(cw < c)
            {
                if(cw > bestw)      //新最优解出现
                {
                    bestx[i] = YES;
                    bestw = cw;
                    return YES;
                }
            }
            else if(cw == c)       //真最优解出现,这里不还原cw,因为直接一直返回知道结束递归
            {
            	bestx[i] = YES;
                return RETURNBACK;
            }
            else                   //没有出现
            {
                cw -= w[i];
                if(cw > bestw)     //新最优解出现
                {
                    bestx[i] = NO;
                    return YES;
                }
            }
            return NO;
        }

        /*初始化记录*/
        int q = NO;
        int p = NO;
        r -= w[i];

        /*当可以装下时*/
        if(cw + w[i] < c)
        {
            cw += w[i];
            q = Backtrack(i+1);
            if(q >= YES)      //新最优解出现
            {
                bestx[i] = YES;
            }
            if(RETURNBACK == q)     //真的最优解出现,直接返回
            {
                return RETURNBACK;
            }
            cw -= w[i];
        }

        /*当刚好装满时*/
        else if(cw + w[i] == c)
        {
            bestw = c;
            bestx[i] = YES;
            return RETURNBACK;
        }

        /*当不装时,减少枝叶*/
        if(cw + r > bestw)      //减小一定不是最优解的子树
        {
            p = Backtrack(i+1);
            if(YES == p)        //当新最优解出现
            {
                bestx[i] = NO;
                return YES;
            }
            else if(RETURNBACK == p)        //当真最优解出现
            {
                bestx[i] = NO;
                return RETURNBACK;
            }
        }

        /*返回结果*/
        r += w[i];      //还原r,避免影响上一层
        if(NO == q + p)
        {
            return NO;
        }
        return YES;     //这个YES是当可以装下时的返回
    }

    int Loading::MaxLoading(int* w,int n,int c,int r,int* x)
    {
        /*初始化类*/
        this->bestx = x;        //这里是直接给地址
        this->w = w;
        this->r = r;
        this->c = c;
        this->cw = 0;
        this->n = n;
        this->bestw = 0;

        /*计算结果*/
        this->Backtrack(0);       //注意我是从0开始的递归,与网上广为流传的从1开始不一样

        /*返回结果*/
        return this->bestw;
    }

    int main()
    {
        int c1 = 0;
        int c2 = 0;
        cout << "请输入两个船的载重量,一号为小箱子,二号为大箱子" << endl;
        cin >> c1 >> c2;

        int n = 0;
        cout << "请输入个数" << endl;
        cin >> n;

        /*创建记录的数据结构*/
        int* w = new int[n];        //每个箱子的重量
        int* x = new int[n];
        int r = 0;

        /*记录数据*/
        cout << "请输入每个箱子的重量" << endl;
        for(int i = 0; i < n; i++)
        {
            cin >> w[i];
            r += w[i];
        }

        /*比较大小,判断是否可以装完*/
        if(r > (c1+c2))
        {
            cout << "想多了,拿命给你装?" << endl;
            return 0;
        }
        else
        {
            /*创建计算的数据结构*/
            Loading X;
            int backall = 0;        //记录返回值
            int* x = new int[n];
            memset(x,0,n*sizeof(int));      //初始化内存

            /*判断结果*/
            backall = X.MaxLoading(w,n,c1,r,x);
            if(backall + c2 >= r)
            {
                cout << "可以完全装完" << endl;
                cout << "一号箱装" << backall << endl;
                cout << "二号箱装" << r - backall << endl;
                cout << "具体如下:" << endl;
                for(int i = 0; i < n; i++)
                {
                    if(YES == x[i])
                    {
                        cout << "第" << i+1 << "个箱子装在一号船上" << endl;
                    }
                    else
                    {
                        cout << "第" << i+1 << "个箱子装在二号船上" << endl;
                    }
                }
            }
            else
            {
                cout << "无法装下" << endl;
            }
        }

        /*释放动态内存*/
        delete[] w;
        delete[] x;

        return 1;
    }


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值