回溯法:最优装载问题

大家好,我是连人。本期讲述回溯法中的最优装载问题。

以简单的语言说,就是给定两艘船,要求一批货物分别装入。

这道问题采用“先尽可能以最大载重装一艘船,再以剩下的货物装另一艘”。

这样,我们就将问题简化为了0-1背包问题。采用回溯法构建解空间,之后遍历即可。思路很简单,代码的注释我也写的很详细了。

def traceback(depth):
    global n, goods, ship, best_arrange, now_arrange, best_load, now_load, remain

    if depth >= n:                 # 遍历到叶节点,取较大值
        if now_load > best_load:
            best_arrange = now_arrange
            best_load = now_load
        return

    remain -= goods[depth]         # 将当前处理货物从剩余中扣去

    if now_load + goods[depth] <= ship:    # 如果加了这件货物没超最大载重
        now_arrange[depth] = 1             # 那就将这件货物先记入当前解向量
        now_load += goods[depth]           # 并且将货物重量记为当前载重
        traceback(depth+1)                 # 继续向下遍历
        now_load -= goods[depth]           # 遍历完之后将载重还原

    if now_load + remain > best_load:      # 如果不加上当前货物的重量还有可能在后方有大于最优装载的可能
        now_arrange[depth] = 0             # 就不加入当前货物
        traceback(depth+1)                 # 进行遍历 这个if中的思路不是"剪枝",而是多长了一个有可能的枝条

    remain += goods[depth]


def result_out():
    global best_arrange, best_load, ship, n, goods
    l = 0
    for i in range(0, n):
        if best_arrange[i] == 0:
            l += goods[i]
    if l > ship:
        print('无法装载')
    else:
        print('可以装载')
        print('第一艘船装载:', end='')
        for i in range(0, n):
            if best_arrange[i] == 1:
                print(i, end=' ')
        print()
        print('第二艘船装载:', end='')
        for i in range(0, n):
            if best_arrange[i] == 0:
                print(i, end=' ')


if __name__ == '__main__':
    n = 3                          # 货物数量
    goods = [40, 40, 10]           # 货物
    ship = 50                      # 船的最大载重
    best_arrange = [0, 0, 0]       # 最优解向量
    now_arrange = [0, 0, 0]        # 遍历时当前解向量
    best_load = 0                  # 最优解时第一艘船的载重
    now_load = 0                   # 遍历时当前载重
    remain = sum(goods)            # 剩余货物重量
    traceback(0)
    result_out()

转载注明出处。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值