一、实验目的
1. 熟悉分支限界法的基本思想;
2. 使用分支限界法分析、解决问题;
3. 实现算法。
二、实验内容
- 分析装载问题的子集树
- 实现分支限界法解决装载问题
三、问题分析
装载问题给定n个集装箱,要求在不超过轮船载重量c的前提下,将尽可能多的集装箱装上轮船。装载问题的解空间是一棵子集树,采用队列式分支限界法来解决,该算法只求出所要求的最优值。
四、算法描述
分支限界法是一种求解最优化问题的搜索算法,在解决装载问题时,分支限界法可以通过不断扩展状态空间,并尝试所有可能的物品组合,在比较最佳的组合之后找到最优解。
分支限界法解决装载问题的算法设计如下:
1.定义一个先进先出队列Q,初始化队列时,在尾部增加一个-1标记,作为分层标志。当一层结束时,在队列尾部增加一个-1标志。
2.定义 Ew 表示扩展节点相对应的载重量,bestw 表示当前最优载重量,r 为剩余集装箱的质量。
3.计算剩余集装箱 r 的总重量,即将第一个节点(根节点)取出并进行检查,得到左子树或右子树的重量,检查约束条件若满足则更新 bestw,并将新的左子树加入队列,如果右子树可行,则将原 Ew 加入队列。
4.从队列中取出队头元素Ew并将其设为当前扩展节点的载重量,并将该节点的所有子节点压入队列中。
5.当队头元素为 -1 时,表示该层已经遍历完毕,弹出队头,将 -1 添加到队尾作为同层遍历结束的标志。
6.进行下一层遍历,i++ 并计算 r 剩余集装箱中去掉当前位置 i 的重量。不断重复上述步骤进行搜索操作,直到队列为空为止。
7.返回最优载重量bestw。
五、运行结果
六、源代码
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
#define NUM 100
int n;//集装箱的数量
int c;//轮船的载重量
int w[NUM];//集装箱的质量数组
int MaxLoading()
{
queue<int> Q;//定义活结点队列
Q.push(-1);
int i = 0;//当前扩展结点所在层
int Ew = 0;//扩展结点相对应的载重量
int bestw = 0;//当前最优载重量
int r = 0;//剩余集装箱的质量
for(int j=1; j<n; j++)
r += w[j];
while (true)//搜索子空间树
{
int wt = Ew+w[i];//检查左子树
if (wt<=c)//检查约束条件
{
if (wt>bestw) bestw = wt;
//加入活结点队列
if (i<n-1) Q.push(wt);
}
//检查右子树
if (Ew+r>bestw && i<n-1)
Q.push(Ew);
Ew = Q.front();//从队列中取出活结点
Q.pop();
if (Ew==-1)
{
if (Q.empty()) //若队列为空,搜索结束
return bestw;
Q.push(-1);//同层结点尾部标志
Ew = Q.front();//从队列中取出活结点
Q.pop();
i++;//进入下一层
r -= w[i];
}
}
return bestw;//返回最优载重量
}
int main()
{
cout<<"请输入集装箱的数量:";
cin>>n;
cout<<"请输入轮船的载重量:";
cin>>c;
cout<<"请依次输入各个集装箱的重量:";
for(int i=0; i<n; i++){
cin>>w[i];
}
int ans=MaxLoading();
if (ans)
cout<<"最优装载量为:"<<ans<<endl;
else cout<<"Error"<<endl;
return 0;