装载问题-分支限界法

装载问题-分支限界法(队列式分支限界法,优先队列式分支限界法)

问题描述

有n个集装箱要装上2艘载重量分别为c1和c2的轮船,其中集装箱i的重量为wi,且
在这里插入图片描述

问题:

是否有一个合理的装载方案,可将这n个集装箱装上这2艘轮船?如果有,找出一种装载方案。
例如:当n=3, c1=c2=50

(1)若w=[10, 40, 40]

可将集装箱1和集装箱2装上第一艘轮船,而将集装箱3装上第二艘轮船;

(2)如果w=[20, 40, 40]

则无法将这3个集装箱都装上船;

队列式分支限界法

解装载问题的队列式分支限界法仅求出所要求的最优值,稍后进一步构造最优解。
首先检测当前扩展结点的左儿子结点是否为可行结点。如果是,则将其加入到活结点队列Q中。
然后,将其右儿子结点加入到活结点队列中(右儿子结点一定是可行结点)。2个儿子结点都产生后,当前扩展结点被舍弃。
活结点队列中,队首元素被取出作为当前扩展结点。
活结点队列已空,算法终止。

// QNode.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<queue>

using namespace std;

template<class Type>
class QNode
{
    template<class Type>
    friend Type MaxLoading(Type*, Type ,int, int*);
    template<class Type>
    friend void EnQueue(queue<QNode<Type>*>&, Type, int, int, Type, QNode<Type>*, QNode<Type>* &, int*, bool);
private:
    QNode* parent;
    bool LChind;
    Type weight;
};

template<class Type>
void EnQueue(queue<QNode<Type>*>& Q, Type wt, int i, int n, Type bestw, QNode<Type>* E, QNode<Type>* &bestE, int* bestx, bool ch)
{
    if (i == n)
    {
        if (wt == bestw)
        {
            bestE = E;
            bestx[n] = ch;
        }
        return;
    }
    QNode<Type>* b;
    b = new QNode<Type>;
    b->weight = wt;
    b->parent = E;
    b->LChind = ch;
    Q.push(b);
}

template<class Type>
Type MaxLoading(Type* w, Type c, int n, int* bestx)
{
    queue<QNode<Type>*> Q;
    Q.push(nullptr);
    int i = 1;
    Type cw = 0,
        bestw = 0,
        r = 0;
    for (int i = 2; i <= n; i++)
        r += w[i];
    QNode<Type>* E = nullptr,
        * bestE=nullptr;
    while (true)
    {
        Type wt = cw + w[i];
        if (wt < c)
        {
            if (wt > bestw)
                bestw = wt;
            EnQueue<Type>(Q, wt, i, n, bestw, E, bestE, bestx, true);
        }
        if(cw+r>=bestw)
            EnQueue<Type>(Q, cw, i, n, bestw, E, bestE, bestx, false);
        E = Q.front();
        Q.pop();
        if (!E)
        {
            if (Q.empty())
                break;
            Q.push(nullptr);
            E = Q.front();
            Q.pop();
            i++;
            r -= w[i];
        }
        cw = E->weight;
    }
    for (int j = n - 1; j > 0; j--)
    {
        bestx[j] = bestE->LChind;
        bestE = bestE->parent;
    }
    for (int i = 1; i <= n; i++)
        cout << bestx[i] << "\t";
    cout << endl;
    return bestw;
}


int main()
{
    int w[4] = { 0,20,40,40 };
    int c = 50;
    int n = 3;
    int* bestx = new int[4];
    cout<<MaxLoading<int>(w, c, n, bestx)<<endl;
    
    return 0;
}

优先队列式分支限界法

解装载问题的优先队列式分支限界法用最大优先队列存储活结点表。
活结点x在优先队列中的优先级定义为从根结点到结点x的路径所相应的载重量Ew(即:当前扩展结点船的载重量Ew)再加上剩余集装箱的重量r之和(即:将上界Ew+r定义为结点优先级)。
优先队列中优先级最大的活结点成为下一个扩展结点。
子集树中叶结点所相应的载重量与其优先级(上界值)相同,即:该叶子结点的上界值等于当前叶子结点处船的重量Ew。
在优先队列式分支限界法中,一旦有一个叶结点成为当前扩展结点,则可以断言该叶结点所相应的解即为最优解。此时可终止算法。

// LoadHeap.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<queue>

using namespace std;

template<class Type>
class bbnode
{
    template<class Type>
    friend class Loading;
    template<class Type>
    friend class HeapNode;
private:
    bbnode<Type>* parent;
    bool LChild;
};

template<class Type>
class HeapNode
{
    template<class Type>
    friend class Loading;
public:
    operator Type ()const { return uweight; }
private:
    Type level,
        uweight;
    bbnode<Type>* ptr;
};

template<class Type>
class Loading
{
    friend int main(void);
private:
    Type MaxLoad();
    void AddLiveNode(priority_queue<HeapNode<Type>>& H, Type lev, Type weight, bbnode<Type>* E, bool ch);
    Type cw,//当前的重量
        bestw,//最好重量
        * w,//物品重量
        c,//船的重量
        n;
    Type *r;
    Type bestx[4];
};

template<class Type>
Type Loading<Type>::MaxLoad()
{
    priority_queue<HeapNode<Type>> H;
    bbnode<Type>* E = nullptr;
    int t = 1;
    cw = 0;
    r = new Type[n + 1];
    r[n] = 0;
    for (int j = n - 1; j > 0; j--)
        r[j] = r[j + 1] + w[j + 1];
    while (t!=n+1)
    {
        if (cw + w[t] <= c)
            AddLiveNode(H, t+1, cw + w[t] + r[t], E, true);
        AddLiveNode(H, t+1, cw + r[t], E, false);
        HeapNode<Type> N;
        N = H.top();
        H.pop();
        E = N.ptr;
        t = N.level;
        cw = N.uweight - r[t-1];
    }
    for (int i = 3; i > 0; i--)
    {
        bestx[i] = E->LChild;
        E = E->parent;
    }
    for (int i = 1; i <=n; i++)
    {
        cout << bestx[i] << "\t";
    }
    cout << endl;
    return cw;
}

template<class Type>
void Loading<Type>::AddLiveNode(priority_queue<HeapNode<Type>>& H, Type lev, Type weight, bbnode<Type>* E, bool ch)
{
    bbnode<Type> *b = new bbnode<Type>;
    b->parent = E;
    b->LChild = ch;
    HeapNode<Type> N;
    N.level = lev;
    N.ptr = b;
    N.uweight = weight;
    H.push(N);
}

int main()
{

    int w[] = {0,20,40,40};
    Loading<int> load;
    load.w = w;
    load.c = 50;
    load.n = 3;
    cout<<load.MaxLoad()<<endl;
    return 0;
}

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
装载问题是一类优化问题,其目标是在给定的一些物品中选择若干个物品,使得其总重量不超过限制且总价值最大化。下面是使用分支限界法求解装载问题的 Python 代码: ``` class Item: def __init__(self, weight, value): self.weight = weight self.value = value def load(capacity, items): items.sort(key=lambda x: x.value / x.weight, reverse=True) # 按单位价值排序 n = len(items) best_value = 0 # 当前最优解 best_items = [] # 当前最优解对应的物品列表 def bound(node): if node.weight > capacity: return 0 # 超出容量,不可行 value_bound = node.value weight_bound = node.weight j = node.level + 1 while j < n and weight_bound + items[j].weight <= capacity: value_bound += items[j].value weight_bound += items[j].weight j += 1 if j < n: value_bound += (capacity - weight_bound) * items[j].value / items[j].weight return value_bound def dfs(node): nonlocal best_value, best_items if node.level == n - 1: if node.value > best_value: best_value = node.value best_items = [items[i] for i in node.path] return if node.value + bound(node) <= best_value: return # 剪枝 # 不选当前物品 dfs(Node(node.level + 1, node.weight, node.value, node.path)) # 选当前物品 if node.weight + items[node.level + 1].weight <= capacity: dfs(Node(node.level + 1, node.weight + items[node.level + 1].weight, node.value + items[node.level + 1].value, node.path + [node.level + 1])) class Node: def __init__(self, level, weight, value, path): self.level = level self.weight = weight self.value = value self.path = path dfs(Node(-1, 0, 0, [])) return best_value, best_items ``` 代码中,`Item` 类表示一个物品,包含重量和价值两个属性。`load` 函数接受一个容量和一个物品列表作为输入,返回最优解的总价值和所选物品列表。函数中使用了一个 `Node` 类表示搜索树中的节点,包含当前节点的层数、当前已选物品的总重量和总价值、以及已选物品的编号列表。`bound` 函数计算当前节点的上界,即将剩余物品按单位价值从高到低排序后依次加入,直到超出容量为止,然后将剩余部分按单位价值填满。`dfs` 函数是搜索过程的核心,其首先判断当前节点是否是叶子节点,如果是,则更新最优解。否则,先进行一次剪枝,如果当前节点的上界小于等于当前最优解,则直接返回;否则,继续搜索两个子节点,分别对应选或不选当前物品。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值