装载问题

装载问题

问题:假设有两只船,各可以载重c1,c2。同时有n个集装箱,每个集装箱重量为w[i],问能否将集装箱放入船内,能放入则就最优载重。
在这里插入图片描述
分析
其实和背包问题如出一辙。如果一个给定的装载问题有解,则我们采用的策略应该是:先将第一艘轮船尽可能装满,然后将剩余的集装箱上第二艘轮船(如果不能把所有物品装入第二艘船那么问题无解)。将第一艘轮船尽可能装满等价于选取全体集装箱的一个子集,使该子集中集装箱重量之和最接近c1(即求出最解)。由此可知,装载问题等价于特殊的0-1背包问题。
递归算法解决。没有到达叶结点,先考虑是否满足约束条件,若满足就加上该物品(进入左子树),将解加到解数组里面,更新cw即cw+=w[t],再判断下一步(t+1)是否能左走,能则一直向左走,直到遇到叶结点或者cw+w[i]>c1则不能向左走。遇到叶子结点则更新bestw,bestx、不能向左走就只能判断能向右走。然后就要考虑是否需要进入右子树,那就要判断当前的结点是否满足上界函数即cw+r>bestw:满足则进入右子树,回溯到右子树必须得先回到父节点,那么之前在左边加上的质量就要减掉即cw-w[t],然后才可以进入右子树即执行(t+1)步。不满足的话即便把所有的剩余质量都加到船上也不能达到更大的bestw,所以直接舍弃剩余右子树,不再进行搜索。
源代码

#include<iostream>
using namespace std;

#define NUM 100
int n; //集装箱数量
int c1,c2; //轮船载重量
int cw; //当前轮船载重量
int r; //剩余集装箱重量
int w[100],bestw,x[100],bestx[100];  //最优载重,最优解

//t从1开始
void BackTrack(int t)
{
    //到达叶子节点
    if(t>n){
        cout << cw << endl;
        if(cw > bestw){
            for(int i = 1; i <= n; i++){
                if(x[i])
                    bestx[i] = i;
                else
                    bestx[i]=x[i];
            }
            bestw = cw;
            return;
        }
    }else{
        r -= w[t]; //更新剩余集装箱重量
        if(cw + w[t] <= c1){ //没有超出载重量,判断是否可以向左
            x[t] = 1;
            cw += w[t];
            cout << "左:" << t << " " << bestw << endl;
            BackTrack(t+1);
            cw -= w[t]; //cw要还原原先的载重,因为还要判断其他路线才能找到最优解
            
        }
        if(cw + r > bestw){ //判断是否可以向右
            cout << "右:" << t << " " << bestw << endl;
            x[t] = 0;
            BackTrack(t+1);
            
        }
        r += w[t]; //还原剩余集装箱重量走其他路线
    }
}

int main(){
    //读入数据;
    cout << "请输入AB船的容量c1、c2:";
    cin  >> c1 >> c2;
    cout << "输入物品的数量:";
    cin >> n;
    cout << "依次输入物品的质量:";
    for(int i = 1; i <= n; i++){//初始化,bestw=0
        cin >> w[i];
        r += w[i];
    }
    //递归回溯
    BackTrack(1);
    if(r-bestw > c2)//无解
        cout << "没有装载方案" << endl;
    else{//有解
        cout << "最有载重为:" << bestw << endl;
        cout << "分别为第" ;
        for(int i = 1; i <= n; i++)
            if(bestx[i])
                cout << bestx[i] << " ";
        cout << "个箱子" << endl;
    }
    return 0;
}

下面为给的例子和结果
在这里插入图片描述
我把进入左右子树的过程都打了出来,可以很清晰的看到每一个箱子进入cw的过程,已经最优解得到的过程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值