分支限界法实验(最优装载问题)

合集下载

第6章 分支限界法(1-例子)

第6章 分支限界法(1-例子)
5
6.3 装载问题
3. 算法的改进
// 检查右儿子结点 // 检查左儿子结点 Type wt = Ew + w[i]; if (wt <= c) { // 可行结点 右儿子剪枝
if (Ew + r > bestw && i < n) Q.Add(Ew); // 可能含最优解 Q.Delete(Ew);// 取下一扩展结点 提前更新 bestw
5. 优先队列式分支限界法
解装载问题的优先队列式分支限界法用最大优先队列存 储活结点表。 活结点x在优先队列中的优先级定义为从根结点到结点x的 路径所相应的载重量再加上剩余集装箱的重量之和。 优先队列中优先级最大的活结点成为下一个扩展结点。 在优先队列式分支限界法中,一旦有一个叶结点成为当 前扩展结点,则可以断言该叶结点所相应的解即为最优解。 此时可终止算法。
while6.3 (true)装载问题 { // 检查左儿子结点 2. 队列式分支限界法 if (Ew + w[i] <= c) // x[i] = 1 EnQueue(Q, Ew + w[i], bestw, i, n); // 右儿子结点总是可行的 EnQueue(Q, Ew, bestw, i, n); // x[i] = 0 Q.Delete(Ew); // 取下一扩展结点 if (Ew == -1) { // 同层结点尾部 if (Q.IsEmpty()) return bestw; Q.Add(-1); // 同层结点尾部标志 Q.Delete(Ew); // 取下一扩展结点 i++; // 进入下一层 } }
if (wt > bestw) bestw = wt; // 加入活结点队列 if (i < n) Q.Add(wt); }

用分支限界算法解装载问题详解

用分支限界算法解装载问题详解

用分支限界算法解装载问题详解一、实验目的1、理解分支限界法的概念,掌握分支限界法的基本要素。

2、掌握设计分支限界法的一般步骤,针对具体问题,能应用分支限界法求解二、实验内容1、问题描述:有一批共个集装箱要装上2艘载重量分别为C1和C2的轮船,其中集装箱i的重量为Wi,且w1+…+wn<= C1+ C2; 装载问题要求确定是否有一个合理的装载方案可将这个集装箱装上这2艘轮船。

如果有,找出一种装载方案。

2、数据输入:文件输入或键盘输入。

3、要求:1)完成上述问题的队列式分支限界法解决问题,时间为1 次课。

2)独立完成实验及实验报告。

三、实验步骤1、理解方法思想和问题要求。

2、采用编程语言实现题目要求。

3、上机输入和调试自己所写的程序。

4、附程序主要代码:#include <bits/stdc++、h>using namespace std;class MaxHeapQNode{public: MaxHeapQNode*parent; int lchild; int weight; int lev;};structcmp{ bool operator()(MaxHeapQNode *&a, MaxHeapQNode *&b)const { return a->weight < b->weight; }};int n;int c;int bestw;int w[100];int bestx[100];voidInPut(){ scanf("%d %d", &n, &c); for(int i =1; i <= n;++i)scanf("%d", &w[i]);}voidAddAliveNode(priority_queue<MaxHeapQNode *,vector<MaxHeapQNode *>, cmp> &q, MaxHeapQNode *E, int wt, int i, int ch){ MaxHeapQNode *p = new MaxHeapQNode; p->parent = E; p->lchild = ch; p->weight = wt; p->lev = i +1; q、push(p);}voidMaxLoading(){ priority_queue<MaxHeapQNode *,vector<MaxHeapQNode *>, cmp > q; // 大顶堆 //定义剩余重量数组r int r[n +1]; r[n] = 0; for(int j = n-j)r[j] = r[j +1] + w[j +1]; int i =1; MaxHeapQNode *E; int Ew = 0; while(i != n +1){ if(Ew + w[i] <= c){ AddAliveNode(q, E, Ew + w[i] + r[i], i,1); } AddAliveNode(q, E, Ew + r[i], i, 0); //取下一节点 E = q、top(); q、pop(); i = E->lev; Ew = E->weight1]; } bestw = Ew; for(int j = n; j > 0;j){ bestx[j] = E->lchild; E = E->parent; }}void OutPut(){ printf("最优装载量为 %d\n", bestw); printf("装载的物品为 \n"); for(int i =1; i <= n; ++i)if(bestx[i] ==1)printf("%d ", i);}int main(){ InPut(); MaxLoading(); OutPut();}5、实验结果:4、装载问题实验分析:1、将wt<=c和Ew+r>=bestw作为限界判定。

9——分支限界法

9——分支限界法
14

2 例9.1-限界
x3=1
x2=1 4
x1=1 2 x2=0 5
1
x1=0 3 x2=1 6
x2=0
x3=1 x3=0
x3=0 x3=1
x3=0 x3=1 x3=0
7
8

9
10
11 12
13
14
15
W={50,10,10},C1=60。 在此例中,结点3所在分支的所有子树中,装载货物的最 大可能是多少? 20。
20
2 例9.1-算法2 FIFO分支限界
AddLiveNode(folat wt,int i, QNode *E, int ch) { Qnode *b; if (i=n) //叶子 { if (wt>bestw) //目前的最优解 { bestE=E; bestx[n]=ch;} //bestx[n]取值为ch return; } b = new QNode; // 不是叶子, 添加到队列中 b->weight=wt; b->parent=E; b->LChild=ch; add (Q,b) ; }
3 7 14 15


分支搜索法是一种在问题解空间上进行搜索尝试的算法。 所谓“分支”是采用广度优先的策略,依次生成E-结点所 有分支,也就是所有的儿子结点。 和回溯法一样,可以在生成的结点中,抛弃那些不满足约 束条件的结点,其余结点加入活结点表。然后从表中选择 一个结点作为下一个E-结点。 选择下一个E-结点方式的不同导致几种分支搜索方式:
8
2 例9.1 装载问题
子集树
x3=1
x2=1 4
x1=1 2 x2=0 5
1
x1=0 3 x2=1 6

实验五、优先队列式分支限界法解装载问题

实验五、优先队列式分支限界法解装载问题

实验五优先队列式分支限界法解装载问题09电信实验班I09660118 徐振飞一、实验题目实现书本P201所描述的优先队列式分支限界法解装载问题二、实验目的(1)掌握并运用分支限界法基本思想(2)运用优先队列式分支限界法实现装载问题(3)比较队列式分支限界法和优先队列式分支限界法的优缺点三、实验内容和原理(1)实验内容有一批共n个集装箱要装上2艘载重量分别为c1和c2的轮船,其中集装箱i的重量为Wi,且∑=+≤niiccw121,要求确定是否有一个合理的装载方案可将这n个集装箱装上这2艘轮船。

如果有,请给出方案。

(2)实验原理解装载问题的优先队列式分支限界法用最大优先队列存储活结点表。

活结点x在优先队列中的优先级定义为从根结点到结点x的路径所相应的载重量再加上剩余集装箱的重量之和。

优先队列中优先级最大的活结点成为下一个扩展结点。

优先队列中活结点x的优先级为x.uweight。

以结点x为根的子树中所有结点相应的路径的载重量不超过x.uweight。

子集树中叶结点所相应的载重量与其优先级相同。

因此在优先队列式分支限界法中,一旦有一个叶结点成为当前扩展结点,则可以断言该叶结点所相应的解即为最优解,此时终止算法。

上述策略可以用两种不同方式来实现。

第一种方式在结点优先队列的每一个活结点中保存从解空间树的根结点到该活结点的路径,在算法确定了达到最优值的叶结点时,就在该叶结点处同时得到相应的最优解。

第二种方式在算法的搜索进程中保存当前已构造出的部分解空间树,在算法确定了达到最优值的叶结点时,就可以在解空间树中从该叶结点开始向根结点回溯,构造出相应的最优解。

在下面的算法中,采用第二种方式。

四、源程序import parator;import java.util.Iterator;import java.util.PriorityQueue;import java.util.Scanner;public class test5 {public void addLiveNode(PriorityQueue<HeapNode> H,bbnode E,int wt,boolean ch,int lev){bbnode b = new bbnode(E,ch);HeapNode N = new HeapNode(b, wt, lev);H.add(N);}public int maxLoading(int w[],int c,int n,boolean bestx[]){PriorityQueue<HeapNode> H = new PriorityQueue(1000,new comp());/*生成最大堆*/int[] r = new int[n+1];r[n] = 0;for(int j=n-1;j>0;j--){r[j] = r[j+1] + w[j+1];}int i = 1;bbnode E = new bbnode(null,false);int Ew = 0;while(i!=n+1){if(Ew+w[i]<=c){addLiveNode(H, E, Ew+w[i]+r[i], true, i+1);}addLiveNode(H, E, Ew+r[i], false, i+1);HeapNode N;N=H.poll();i = N.level;E = N.ptr;Ew = N.uweight - r[i-1];}//构造最优解for(int j=n;j>0;j--){bestx[j] = E.Lchild;E = E.parent;}return Ew;}public static void main(String[] args){System.out.println("请输入物品总数:");Scanner sc1 = new Scanner(System.in);int n = sc1.nextInt();int[] w = new int[n+1];System.out.println("请输入物品重量:");Scanner sc2 = new Scanner(System.in);for(int i=1;i<=n;i++){w[i] = sc2.nextInt();}System.out.println("请输入箱子重量:");Scanner sc3 = new Scanner(System.in);int c1 = sc3.nextInt();int c2 = sc3.nextInt();boolean[] bestx = new boolean[100];test5 t = new test5();//处理第一个箱子System.out.println("first:"+t.maxLoading(w, c1, n, bestx));System.out.print("可装重为:");int count = 0;for(int i=1;i<=n;i++){if(bestx[i]){count++;System.out.print(w[i]+" "); /*输出一个可行方案*/ }}System.out.println();/*处理第二个箱子*/int m = n - count;int[] ww = new int[m+1];int k = 1;for(int i=1;i<=n;i++){if(!bestx[i]){ww[k] = w[i];k++;bestx[i] = false;}}System.out.println();System.out.println("second:"+t.maxLoading(ww, c2, m, bestx));System.out.print("可装重为:");for(int i=1;i<=m;i++){if(bestx[i]){System.out.print(ww[i]+" "); /*输出一个可行方案*/ }}}}/*堆结点类*/class HeapNode{bbnode ptr;int uweight;int level;public HeapNode(){}public HeapNode(bbnode ptr,int uweight,int level){this.ptr = ptr;this.uweight = uweight;this.level = level;}public String toString(){return ""+this.uweight;}}class bbnode{bbnode parent;boolean Lchild;public bbnode(bbnode node,boolean ch){this.parent = node;this.Lchild = ch;}}//定义比较器类class comp implements Comparator<HeapNode>{@Overridepublic int compare(HeapNode o1, HeapNode o2) {int dif = o1.uweight-o2.uweight;if(dif>0){return -1;}else if(dif==0){return 0;}else{return 1;}}}五、实验结果和分析a.输入格式说明:(1)首先输入物品总数量(2)第二栏输入所有物品重量(3)第三栏输入2个箱子的重量b.输出格式说明:(1)首先输出first的字样,后面的数字表示第一个箱子所能装载的最大重量,紧接着的一行输出一种可以选择装载的方案(2)Second字样后面的数字表示第二个箱子所能装载的最大重量,紧接着的一行输出一种可行方案经过分析,上述结果正确。

算法——分支限界法(装载问题)

算法——分支限界法(装载问题)

算法——分⽀限界法(装载问题)对⽐回溯法回溯法的求解⽬标是找出解空间中满⾜约束条件的所有解,想必之下,分⽀限界法的求解⽬标则是找出满⾜约束条件的⼀个解,或是满⾜约束条件的解中找出使某⼀⽬标函数值达到极⼤或极⼩的解,即在某种意义下的最优解。

另外还有⼀个⾮常⼤的不同点就是,回溯法以深度优先的⽅式搜索解空间,⽽分⽀界限法则以⼴度优先的⽅式或以最⼩耗费优先的⽅式搜索解空间。

分⽀限界法的搜索策略在当前节点(扩展节点)处,先⽣成其所有的⼉⼦节点(分⽀),然后再从当前的活节点(当前节点的⼦节点)表中选择下⼀个扩展节点。

为了有效地选择下⼀个扩展节点,加速搜索的进程,在每⼀个活节点处,计算⼀个函数值(限界),并根据函数值,从当前活节点表中选择⼀个最有利的节点作为扩展节点,使搜索朝着解空间上有最优解的分⽀推进,以便尽快地找出⼀个最优解。

分⽀限界法解决了⼤量离散最优化的问题。

选择⽅法1.队列式(FIFO)分⽀限界法队列式分⽀限界法将活节点表组织成⼀个队列,并将队列的先进先出原则选取下⼀个节点为当前扩展节点。

2.优先队列式分⽀限界法优先队列式分⽀限界法将活节点表组织成⼀个优先队列,并将优先队列中规定的节点优先级选取优先级最⾼的下⼀个节点成为当前扩展节点。

如果选择这种选择⽅式,往往将数据排成最⼤堆或者最⼩堆来实现。

例⼦:装载问题有⼀批共n个集装箱要装上2艘载重量分别为c1,c2的轮船,其中集装箱i的重量为wi,且要求确定是否有⼀个合理的装载⽅案可将这n个集装箱装上这2艘轮船。

可证明,采⽤如下策略可以得到⼀个最优装载⽅案:先尽可能的将第⼀艘船装满,其次将剩余的集装箱装到第⼆艘船上。

代码如下://分⽀限界法解装载问题//⼦函数,将当前活节点加⼊队列template<class Type>void EnQueue(Queue<Type> &Q, Type wt, Type &bestw, int i, int n){if(i == n) //可⾏叶结点{if(wt>bestw) bestw = wt ;}else Q.Add(wt) ; //⾮叶结点}//装载问题先尽量将第⼀艘船装满//队列式分⽀限界法,返回最优载重量template<class Type>Type MaxLoading(Type w[],Type c,int n){//初始化数据Queue<Type> Q; //保存活节点的队列Q.Add(-1); //-1的标志是标识分层int i=1; //i表⽰当前扩展节点所在的层数Type Ew=0; //Ew表⽰当前扩展节点的重量Type bestw=0; //bestw表⽰当前最优载重量//搜索⼦集空间树while(true){if(Ew+w[i]<=c) //检查左⼉⼦EnQueue(Q,Ew+w[i],bestw,i,n); //将左⼉⼦添加到队列//将右⼉⼦添加到队列即表⽰不将当前货物装载在第⼀艘船EnQueue(Q,Ew,bestw,i,n);Q.Delete(Ew); //取下⼀个节点为扩展节点并将重量保存在Ewif(Ew==-1) //检查是否到了同层结束{if(Q.IsEmpty()) return bestw; //遍历完毕,返回最优值Q.Add(-1); //添加分层标志Q.Delete(Ew); //删除分层标志,进⼊下⼀层i++;}}}算法MaxLoading的计算时间和空间复杂度为O(2^n).上述算法可以改进,设r为剩余集装箱的重量,当Ew+r<=bestw的时候,可以将右⼦树剪去。

分支限界法实现实验报告

分支限界法实现实验报告
1.队列式(FIFO)分支限界法
队列式分支限界法将活节点表组织成一个队列,并将队列的先进先出原则选取下一个节点为当前扩展节点。
2.优先队列式分支限界法
优先队列式分支限界法将活节点表组织成一个优先队列,并将优先队列中规定的节点优先级选取优先级最高的下一个节点成为当前扩展节点。如果选择这种选择方式,往往将数据排成最大堆或者最小堆来实现。
for (j=0;j<City_Size;j++){
temp_x[j]=Best_Cost_Path[j];
}
temp_x[pNode->x[pNode->s+1]] = Best_Cost_Path[i];
temp_x[i] = Best_Cost_Path[pNode->s+1];
Node* pNextNode = new Node;
int edge2 = City_Graph[(pNode->x)[City_Size-1]][(pNode->x)[0]];
if(edge1 >= 0 && edge2 >= 0 && (pNode->cc+edge1+edge2) < Best_Cost){
Best_Cost = pNode->cc + edge1+edge2;
二、实验过程记录:
打开MicrosoftC++2008,键入代码进行编程:
源代码为:
#include <stdio.h>
#include "stdafx.h"
#include <istream>

分支与限界:货物装载问题

分支与限界:货物装载问题

分支与限界:货物装载问题课程名称:**************院系:************************学生姓名:******学号:************专业班级:***************************** 指导教师:*******2013年12月27日分支与限界:货物装载问题摘要:在现实生活中,我们会经常遇见货物装载问题,如何解决货物装载问题,获取利润的最大化,花费最少的而得到更多的东西,是人们一直都要考虑的问题。

在广泛的解决问题中,人们一般采用分支限界算法解决这样的问题。

分支限界法是由分支策略和限界策略两部分组成的。

分枝定界法是一个用途十分广泛的算法,运用这种算法的技巧性很强,不同类型的问题解法也各不相同。

该算法在具体执行时,把全部可行的解空间不断分割为越来越小的子集(称为分支),并为每个子集内的解的值计算一个下界或上界(称为定界)。

在每次分支后,对凡是界限超出已知可行解值那些子集不再做进一步分支。

这样,解的许多子集(即搜索树上的许多结点)就可以不予考虑了,从而缩小了搜索范围。

该算法在具体执行时,把全部可行的解空间不断分割为越来越小的子集(称为分支),并为每个子集内的解的值计算一个下界或上界(称为定界)。

在每次分支后,对凡是界限超出已知可行解值那些子集不再做进一步分支。

这样,解的许多子集(即搜索树上的许多结点)就可以不予考虑了,从而缩小了搜索范围。

分支策略体现在对问题空间是按广度优先的策略进行搜索,限界策略是为了加速搜索速度而采用启发信息剪枝的策略。

在分支限界法,经常采用的是分支搜索法,分支搜索法是一种在问题空间上进行搜索尝试的算法。

所谓分支是采用广度优先的策略,依次搜索E-结点的所有的分支,也就是所有的相邻结点。

和回溯法一样,在生成的节点中,抛弃那些不满足的约束条件的的结点,其余结点加入活结点表。

在分支搜索的算法中,人们经常会采用FIFO搜索和优先队列式搜索。

分支限界法经典案例算法分析

分支限界法经典案例算法分析

3. 算法的改进
6.3 装载问题
// 检查左儿子结点 Type wt = Ew + w[i]; // 左儿子结点的重量 if (wt <= c) { // 可行结点 提前更新 if (wt > bestw) bestw = wt; bestw // 加入活结点队列 if (i < n) Q.Add(wt); } 右儿子剪枝 // 检查右儿子结点 if (Ew + r > bestw && i < n) Q.Add(Ew); // 可能含最优解 Q.Delete(Ew); // 取下一扩展结点
6.3 装载问题
1. 问题描述
有一批共个集装箱要装上2艘载重量分别为C1和C2的轮船, 其中集装箱i的重量为Wi,且 n
w
i 1
i
c1 c2
装载问题要求确定是否有一个合理的装载方案可将这个 集装箱装上这2艘轮船。如果有,找出一种装载方案。 容易证明:如果一个给定装载问题有解,则采用下面的 策略可得到最优装载方案。 (1)首先将第一艘轮船尽可能装满; (2)将剩余的集装箱装上第二艘轮船。
定义移动方向 的相对位移
设置边界的围 墙 for (int i = 0; i <= m+1; i++) grid[0][i] = grid[n+1][i] = 1; // 顶部和底部 for (int i = 0; i <= n+1; i++) grid[i][0] = grid[i][m+1] = 1; // 左翼和右翼
6.3 装载问题
将第一艘轮船尽可能装满等 价于选取全体集装箱的一个 子集,使该子集中集装箱重 量之和最接近。由此可知, 装载问题等价于以下特殊的 0-1背包问题。 例如:

实验指导书-实验8-分支限界法-2

实验指导书-实验8-分支限界法-2

算法设计与分析实验指导书(计算机科学与技术系)编写兰州交通大学电子与信息工程学院2018年3月目录实验7 分支限界法-1 (3)一、实验目的 (3)二、实验仪器设备 (3)三、实验原理 (3)四、实验内容及注意事项 (3)五、实验步骤 (3)5.1 装载问题 (3)1)最基本的队列式分支限界法。

(3)2) 改进的队列式分支限界法 (4)3)队列式分支限界法,包含最优解 (5)4) 优先队列式分支限界法,包含最优解。

(8)六、实验数据整理与结果分析 (10)七、实验总结 (11)八、实验报告 (11)实验7 分支限界法-1一、实验目的(1)掌握分支限界法的各种不同的具体方法,包括队列式、改进的队列式以及优先队列式的区别。

(2)通过实验掌握分支限界法思想和方法;(3)培养学生的动手能力。

二、实验仪器设备(1)计算机;(2)C++编译调试环境。

三、实验原理掌握将算法转换为可运行程序的步骤。

四、实验内容及注意事项(1)装载问题。

五、实验步骤5.1 装载问题1)最基本的队列式分支限界法。

只计算最优值,没有计算最优解。

#include"stdafx.h"#include<cstdlib>#include<iostream>#include<queue>using namespace std;//子函数,将当前活节点加入队列template<class Type>void EnQueue(queue<Type> &Q, Type wt, Type &bestw, int i, int n){if (i == n) //可行叶结点{if (wt>bestw) bestw = wt;}else Q.push(wt); //非叶结点}//装载问题先尽量将第一艘船装满//队列式分支限界法,返回最优载重量template<class Type>Type MaxLoading(Type w[], Type c, int n){//初始化数据queue<Type> Q; //保存活节点的队列Q.push(-1); //-1的标志是标识分层int i = 1; //i表示当前扩展节点所在的层数Type Ew = 0; //Ew表示当前扩展节点的重量Type bestw = 0; //bestw表示当前最优载重量//搜索子集空间树while (true){if (Ew + w[i] <= c) //检查左儿子EnQueue(Q, Ew + w[i], bestw, i, n); //将左儿子添加到队列//将右儿子添加到队列即表示不将当前货物装载在第一艘船EnQueue(Q, Ew, bestw, i, n);Ew = Q.front(); Q.pop(); //取下一个节点为扩展节点并将重量保存在Ewif (Ew == -1) //检查是否到了同层结束{if (Q.empty()) return bestw; //遍历完毕,返回最优值Q.push(-1); //添加分层标志Ew = Q.front(); Q.pop(); //删除分层标志,进入下一层i++;}}return bestw;}int main(int argc, char* argv[]){int w[5] = { 0, 1, 2, 3 };int c = 5;int n = 3;int bestp = MaxLoading(w, c, n);cout << "best p=" << bestp << endl;return 0;}2) 改进的队列式分支限界法加入了进入右子树的上界函数。

分枝限界法实验报告(3篇)

分枝限界法实验报告(3篇)

第1篇一、实验目的1. 理解并掌握分枝限界法的基本原理和实现方法。

2. 通过实际编程,运用分枝限界法解决实际问题。

3. 比较分析分枝限界法与其他搜索算法(如回溯法)的优缺点。

4. 增强算法设计能力和编程实践能力。

二、实验内容本次实验主要涉及以下内容:1. 分支限界法的基本概念和原理。

2. 分支限界法在单源最短路径问题中的应用。

3. 分支限界法的实现步骤和代码编写。

4. 分支限界法与其他搜索算法的对比分析。

三、实验环境1. 操作系统:Windows 102. 编程语言:Python3.83. 开发环境:PyCharm四、实验步骤1. 算法描述:分支限界法是一种用于解决组合优化问题的算法,其基本思想是在问题的解空间树中,按照一定的搜索策略,优先选择有潜力的节点进行扩展,从而减少搜索空间,提高搜索效率。

2. 程序代码:下面是使用Python实现的分支限界法解决单源最短路径问题的代码示例:```pythonimport heapqclass Node:def __init__(self, vertex, distance, parent): self.vertex = vertexself.distance = distanceself.parent = parentdef __lt__(self, other):return self.distance < other.distancedef branch_and_bound(graph, source):初始化优先队列和已访问节点集合open_set = []closed_set = set()添加源节点到优先队列heapq.heappush(open_set, Node(source, 0, None))主循环,直到找到最短路径while open_set:弹出优先队列中最小距离的节点current_node = heapq.heappop(open_set)检查是否已访问过该节点if current_node.vertex in closed_set:continue标记节点为已访问closed_set.add(current_node.vertex)如果当前节点为目标节点,则找到最短路径if current_node.vertex == target:path = []while current_node:path.append(current_node.vertex)current_node = current_node.parentreturn path[::-1]遍历当前节点的邻居节点for neighbor, weight in graph[current_node.vertex].items():if neighbor not in closed_set:计算新节点的距离distance = current_node.distance + weight添加新节点到优先队列heapq.heappush(open_set, Node(neighbor, distance, current_node))没有找到最短路径return None图的表示graph = {0: {1: 2, 2: 3},1: {2: 1, 3: 2},2: {3: 2},3: {1: 3}}源节点和目标节点source = 0target = 3执行分支限界法path = branch_and_bound(graph, source)print("最短路径为:", path)```3. 调试与测试:在编写代码过程中,注意检查数据结构的使用和算法逻辑的正确性。

简述分支限界法的基本步骤与实现方法

简述分支限界法的基本步骤与实现方法

1 分支界限法1.1 基本思想对有约束条件的最优化问题的所有可行解(数目有限)空间进行搜索。

该算法在具体执行时,把全部可行的解空间不断分割为越来越小的子集(称为分支),并为每个子集内的解的值计算一个下界或上界(称为界限)。

在每次分支后,对凡是界限超出已知可行解值的那些子集不在做进一步分支。

这样就缩小了搜索范围。

这一过程一直进行到找出可行解为止,该可行解的值不大于任何子集的界限。

1.2 搜索策略在扩展结点处,先生成其所有的儿子结点(分支),然后再从当前的活结点表中选择下一个扩展结点。

为了有效地选择下一扩展结点,加速搜索的进程,在每一个活结点处,计算一个函数值(限界),并根据函数值,从当前活结点表中选择一个最有利的结点作为扩展结点,使搜索朝着解空间上有最优解的分支推进,以便尽快地找出一个最优解。

1.3 队列式按照队列先进先出(FIFO)原则选取下一个节点为扩展节点。

1.4* 优先队列式按照优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。

2. 典型案例2.1 装载问题2.1.1 问题描述集装箱装载问题要求确定在不超过轮船载重量的前提下,将尽可能多的集装箱装上轮船。

2.1.2 约束函数和限界条件约束函数:当 Ew+wi > c 对扩展结点的左子树剪枝限界函数:当 Ew+r <= bestw 对扩展结点的右子树剪枝2.1.3 队列式分支界限法求解(案例解释)轮船的载重量为c=80、集装箱个数n=4、重量分别为18 7 25 36。

定义一个先进先出(FIFO)队列Q,初始化队列时,在尾部增加一个 -1 标记。

这是一个分层的标志,当一层结束时,在队列尾部增加一个 -1 标志。

定义扩展结点相应的载重量为Ew,剩余集装箱的重量为r,当前最优载重量为bestw。

没到一个结点就要计算bestw、r、Ew,然后进行约束函数和限界函数的判断,如果不满足约束函数则对左子树剪枝,不满足限界函数对右子树进行剪枝。

旅行售货员问题(分支限界法)

旅行售货员问题(分支限界法)

旅⾏售货员问题(分⽀限界法)⼀、实验内容运⽤分⽀限界法解决0-1背包问题(或者旅⾏售货员问题、或者装载问题、或者批处理作业调度)使⽤优先队列式分⽀限界法来求解旅⾏售货员问题⼆、所⽤算法基本思想及复杂度分析1.算法基本思想分⽀限界法常以⼴度优先或以最⼩耗费有限的⽅式搜索问题的解空间树。

问题的解空间树是表⽰问题解空间的⼀棵有序树,常见的有⼦集树和排列树。

在搜索问题的解空间树时,分⽀限界法和回溯法的主要区别在于它们对当前扩展节点所采⽤的扩展⽅式不同。

在分⽀限界法中,每⼀个活结点只有⼀次机会成为扩展节点。

活结点⼀旦成为扩展节点,就⼀次性产⽣其所有⼉⼦节点。

在这些⼉⼦节点中,导致不可⾏解或导致⾮最优解的⼉⼦节点被舍弃,其余⼉⼦节点被加⼊活结点表中。

此后,从活结点表中取下⼀节点为当前扩展节点。

并重复上述节点扩展过程。

这个过程移⾄持续到找到所需的解或活结点表为空为⽌。

从活结点表中选择下⼀扩展节点的不同⽅式导致不同的分⽀限界法。

最常见的有以下两种⽅式:(1)队列式分⽀限界法队列式分⽀限界法将活结点表组织成⼀个队列,并按队列的先进先出原则选取下⼀个节点为当前扩展节点。

(2)优先队列式分⽀限界法优先队列式的分⽀限界法将活结点表组织成⼀个优先队列,并按优先队列中规定的节点优先级选取优先级最⾼的下⼀个节点成为当前扩展节点。

2.问题分析及算法设计问题分析:(1)解旅⾏售货员问题的优先队列式分⽀限界法⽤优先队列存储活结点表。

(2)活结点m在优先队列中的优先级定义为:活结点m对应的⼦树费⽤下界lcost。

(3)lcost=cc+rcost,其中,cc为当前结点费⽤,rcost为当前顶点最⼩出边费⽤加上剩余所有顶点的最⼩出边费⽤和。

(4)优先队列中优先级最⼤的活结点成为下⼀个扩展结点。

(5)排列树中叶结点所相应的载重量与其优先级(下界值)相同,即:叶结点所相应的回路的费⽤(bestc)等于⼦树费⽤下界lcost的值。

算法设计:(1)要找最⼩费⽤旅⾏售货员回路,选⽤最⼩堆表⽰活结点优先队列。

分支限界法求装载问题_物联1301班_刘悦_201308080112

分支限界法求装载问题_物联1301班_刘悦_201308080112

算法分析与设计实验报告第 X次实验输出第1艘船的载重量输出第2艘船的载重量输出待装上轮船的集装箱的重量。

1代表对应集装箱装上轮船,0代表对应集装箱不装上轮船输出所有装上第1艘轮船的集装箱的重量。

输出是否可以将集装箱全部装上两艘轮船。

输出时间。

附录:完整代码#include "MaxHeap.h" #include <iostream>#include<cstdlib>#include<time.h>#include<iomanip>#include<stdlib.h> using namespace std; //定义集装箱的个数const int N = 4;class bbnode;/*============================================================================定义HeapNode类来存储最大堆中顶点的信息。

============================================================================*/ template<class Type>class HeapNode{template<class T>friend void AddLiveNode(MaxHeap<HeapNode<T>>& H,bbnode *E,T wt,bool ch,int lev);template<class Ty>friend Ty MaxLoading(Ty w[],Ty c,int n,int bestx[]);public:operator Type() const{return uweight;}private:bbnode *ptr; //指向活节点在子集树中相应节点的指针Type uweight; //活节点优先级(上界)int level; //活节点在子集树中所处的层序号};/*============================================================================定义bbnode类来定义子集空间树中的结点类型。

《程序设计创新》分支限界法解决01背包问题

《程序设计创新》分支限界法解决01背包问题

《程序设计创新》分支限界法解决01背包问题一、引言分枝限界法通常以广度优先或最小成本(最大收益)优先搜索问题的解空间树。

在分枝限界方法中,每个活动节点只有一次成为扩展节点的机会。

当活动节点成为扩展节点时,将同时生成所有子节点。

这些子节点将丢弃不可执行或非最优解的子节点,并将剩余的子节点添加到活动节点表中。

然后,从活动节点表中选择节点作为当前扩展节点,然后重复上述节点扩展过程。

此过程将持续到所需的解决方案或节点表为空。

二、研究背景在生活或企业活动中,我们常常会遇到一些装在问题。

例如在生活中我们要出去旅游,背包的容量是有限的而要装物品可能很多,但是每个物品的装载优先级肯定是不一样的,那么怎么装更合适一些呢。

在企业活动中,比如轮船集装箱装载问题,集装箱是有限的,那么怎么装载这些货物才能每次都是装载最多的,只有这样企业利润才能最大化。

三、相关技术介绍上述问题就是我们算法中会遇到的背包问题。

而背包问题又分许多。

如背包问题,通常用贪心法解决。

如01背包问题通常用动态规划或者分支限界法解决。

本次我们考虑使用分支限界法来解决01背包问题四、应用示例在01背包问题中,假设有四个物品。

重量W(4,7,5,3),价值V(40,42,25,12),背包重量W为10,试求出最佳装载方案。

定义限界函数: ub = v + (W-w)×(Vi+1/W+1)画出状态空间树的搜索图步骤:①在根结点1,没有将任何物品装入背包,因此,背包的重量和获得的价值均为0,根据限界函数计算结点1的目标函数值为10×10=100;②在结点2,将物品1装入背包,因此,背包的重量为4,获得的价值为40,目标函数值为40 + (10-4)×6=76,将结点2加入待处理结点表PT中;在结点3,没有将物品1装入背包,因此,背包的重量和获得的价值仍为0,目标函数值为10×6=60,将结点3加入表PT 中;③在表PT中选取目标函数值取得极大的结点2优先进行搜索;④在结点4,将物品2装入背包,因此,背包的重量为11,不满足约束条件,将结点4丢弃;在结点5,没有将物品2装入背包,因此,背包的重量和获得的价值与结点2相同,目标函数值为40 + (10-4)×5=70,将结点5加入表PT中;⑤在表PT中选取目标函数值取得极大的结点5优先进行搜索;⑥在结点6,将物品3装入背包,因此,背包的重量为9,获得的价值为65,目标函数值为65 + (10-9)×4=69,将结点6加入表PT中;在结点7,没有将物品3装入背包,因此,背包的重量和获得的价值与结点5相同,目标函数值为40 + (10-4)×4=64,将结点6加入表PT中;⑦在表PT中选取目标函数值取得极大的结点6优先进行搜索;⑧在结点8,将物品4装入背包,因此,背包的重量为12,不满足约束条件,将结点8丢弃;在结点9,没有将物品4装入背包,因此,背包的重量和获得的价值与结点6相同,目标函数值为65;⑨由于结点9是叶子结点,同时结点9的目标函数值是表PT中的极大值,所以,结点9对应的解即是问题的最优解,搜索结束。

货郎担问题分支与限界法

货郎担问题分支与限界法

货郎担问题分支与限界法货郎担问题是一个经典的优化问题,涉及到如何在给定负重限制下,选择携带的物品,使得总价值最大。

该问题有多种解决方法,其中分支与限界法是一种常用的方法。

以下是对分支与限界法的详细解释:一、问题的概述货郎担问题(Knapsack Problem)是一种组合优化问题,旨在确定给定一组物品,如何选择才能使得在满足负重限制的前提下获得最大的总价值。

这个问题在现实生活中有很多应用,如资源分配、时间安排、物流配送等。

二、分支与限界法分支与限界法是一种启发式搜索方法,用于求解复杂的组合优化问题。

货郎担问题可以通过构建状态树来表示,其中每个节点表示一种可能的物品组合,树的深度表示总重量,节点的价值表示该组合的总价值。

分支与限界法通过不断分支和剪枝来缩小状态树的搜索范围,从而提高求解效率。

1. 分支:在状态树的搜索过程中,每次将当前节点进行拆分,生成两个或多个子节点,每个子节点表示一种可能的物品组合。

分支的依据是选择哪种物品继续搜索,或者选择哪些物品组合起来作为一个整体进行搜索。

2. 限界:在分支过程中,对每个子节点设置一个界限值,用于判断是否需要继续搜索该子节点。

界限值的计算方法有多种,常见的有最大价值界限和最小重量界限。

最大价值界限是将当前节点的价值与子节点的价值进行比较,如果子节点的价值小于当前节点的价值,则剪枝该子节点。

最小重量界限是将当前节点的重量与子节点的重量进行比较,如果子节点的重量大于当前节点的重量,则剪枝该子节点。

3. 回溯:在搜索过程中,如果发现当前节点的总价值小于已找到的最优解,则回溯到上一个节点,继续搜索其他分支。

三、算法流程1. 初始化:设置根节点作为初始节点,将其加入到待搜索节点列表中。

2. 主循环:重复以下步骤直到待搜索节点列表为空:a. 从待搜索节点列表中取出一个节点;b. 如果该节点已经搜索过(即其总价值小于已找到的最优解),则跳过该节点;c. 否则,对该节点进行分支;d. 将分支生成的子节点加入到待搜索节点列表中;e. 如果该节点的总价值大于已找到的最优解,则更新最优解;f. 将该节点标记为已搜索;3. 输出最优解。

装载问题5种解决方案

装载问题5种解决方案

算法分析与设计2016/2017(2)实验题目装载问题5种解法学生姓名学生学号学生班级任课教师提交日期2017计算机科学与技术学目录一问题定义 (2)二解决方案 (2)1优先队列式分支限界法求解 (2)1。

3运行结果 (12)2队列式分支限界法求解 (12)2。

1算法分析 (12)2。

2代码 (13)2.3测试截图 (21)3回朔法-迭代 (21)3.1算法分析 (21)3。

2代码 (21)3.3测试截图 (25)4回朔法-递归 (25)4。

1算法分析 (25)4。

2代码 (25)4.3测试截图 (30)5贪心算法 (30)5.1算法分析 (30)5.2代码 (30)5。

3测试截图 (33)一问题定义有一批共有 n 个集装箱要装上两艘载重量分别为 c1 和 c2 的轮船,其中集装箱 i 的重量为 w[i],且重量之和小于(c1 + c2)。

装载问题要求确定是否存在一个合理的装载方案可将这 n 个集装箱装上这两艘轮船。

如果有,找出一种装载方案.二解决方案1优先队列式分支限界法求解1.1算法分析活结点x在优先队列中的优先级定义为从根结点到结点x的路径所相应的载重量再加上剩余集装箱的重量之和。

优先队列中优先级最大的活结点成为下一个扩展结点.以结点x为根的子树中所有结点相应的路径的载重量不超过它的优先级。

子集树中叶结点所相应的载重量与其优先级相同。

在优先队列式分支限界法中,一旦有一个叶结点成为当前扩展结点,则可以断言该叶结点所相应的解即为最优解。

此时可终止算法.1.2代码1。

2-1////MaxHeap.htemplate<class T〉class MaxHeap{public:MaxHeap(int MaxHeapSize = 10);~MaxHeap() {delete []heap;}int Size() const {return CurrentSize;}T Max(){ //查找if (CurrentSize == 0){throw OutOfBounds();}return heap[1];}MaxHeap<T>& Insert(const T&x); //增MaxHeap<T>& DeleteMax(T& x);//删void Initialize(T a[],int size, int ArraySize);private:int CurrentSize,MaxSize;T *heap;// element array};template<class T〉MaxHeap〈T〉::MaxHeap(int MaxHeapSize){// Max heap constructor。

算法设计装载问题的分支限界算法

算法设计装载问题的分支限界算法

算法设计装载问题的分支限界算法下载提示:该文档是本店铺精心编制而成的,希望大家下载后,能够帮助大家解决实际问题。

文档下载后可定制修改,请根据实际需要进行调整和使用,谢谢!本店铺为大家提供各种类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by this editor. I hope that after you download it, it can help you solve practical problems. The document can be customized and modified after downloading, please adjust and use it according to actual needs, thank you! In addition, this shop provides you with various types of practical materials, such as educational essays, diary appreciation, sentence excerpts, ancient poems, classic articles, topic composition, work summary, word parsing, copy excerpts, other materials and so on, want to know different data formats and writing methods, please pay attention!装载问题是一个经典的组合优化问题,也称为背包问题。

分支限界法实验(最优装载问题)

分支限界法实验(最优装载问题)

算法分析与设计实验报告第八次附加实验for(int i=1;i<n;i++)cout<<bestx[i]<<",";cout<<bestx[n]<<")"<<endl; }测试结果当输入物品数量较少时:当输入物品数量较一般时:当输入物品数量较大时:实验心得最优装载就是求解载重量最好的载重方案,之前最优装载采用了贪心算法,这里使用的使分支限界法;其实在使用分支限界法进行了单源最短路径的实现之后,在完成这个实验就显得更简单一点。

分支限界法的算法思想本身还是很好理解的,但是在这个问题中由于涉及到了剪枝的问题,所以新加入了一个0来判断一层是否结束,因为在一层结束的时候,代表该集装箱的情况已经考虑完了,需要考虑下一个集装箱,这个时候就需要更新剩余集装箱的重量,这会影响到一个右子树是否会被剪掉,因此要特别注意。

完整代码(分支限界法)//分支限界法求最优装载#include<iostream>#include<time.h>#include<iomanip>#include<queue>using namespace std;class QNode{friend void Enqueue(queue<QNode *>&,int,int,int,int,QNode *,QNode *&,int *,bool);friend void Maxloading(int *,int,int,int *);private:QNode *parent; //指向父节点的指针bool LChild; //左儿子标志,用来表明自己是否为父节点的左儿子int weight; //节点所相应的载重量};void Enqueue(queue<QNode *>&Q,int wt,int i,int n,int bestw,QNode*E,QNode *&bestE,int bestx[],bool ch){//将活节点加入到队列中if(i==n) //到达叶子节点{if(wt==bestw) //确保当前解为最优解{bestE=E;bestx[n]=ch;}return;}//当不为叶子节点时,加入到队列中,并更新载重、父节点等信息QNode *b;b=new QNode;b->weight=wt;b->parent=E;b->LChild=ch;Q.push(b);}void Maxloading(int w[],int c,int n,int bestx[]) //其中w[]为重量数组¦ { // c为船的总载重量,n为节点数//初始化queue <QNode *>Q; //活节点队列Q.push(0); //将第一个节点加入队列中,并用0表示同层节点的尾部标志int i=1; //当前扩展节点的层数,此时为int Ew=0; //扩展节点相应的载重量int bestw=0; //当前最优载重量int r=0; //剩余集装箱的重量for(int j=2;j<=n;j++) //求得最初的剩余载重量r+=w[j];QNode *E =0; //当前扩展节点QNode *bestE; //当前最优扩展节点//搜索子集空间树while(true){//首先检查左儿子节点int wt=Ew+w[i];if(wt<=c) //左儿子节点为可行结点{if(wt>bestw)bestw=wt;Enqueue(Q,wt,i,n,bestw,E,bestE,bestx,true);//将左节点加入队列}//检查右儿子节点,利用上届函数if(Ew+r>=bestw)Enqueue(Q,Ew,i,n,bestw,E,bestE,bestx,false);//将右节点加入队列E=Q.front(); //取出当前扩展节点Q.pop();if(!E) //到达同层的最末,此时需要更新剩余装箱载重量{if(Q.empty()) break; //此时队列为空Q.push(0); //加入0,表示该层结束E=Q.front();Q.pop();i++; //进入下一层r-=w[i];//更新剩余集装箱的值}Ew=E->weight; //新扩展的节点对应的载重量}//构造当前最优解for(int j=n-1;j>0;j--){bestx[j]=bestE->LChild;bestE=bestE->parent;}cout<<"最优载重量为:"<<bestw<<endl;cout<<"最优载重方式:"<<"(";for(int i=1;i<n;i++)cout<<bestx[i]<<",";cout<<bestx[n]<<")"<<endl;}int main(){int n;cout<<"please input number of node:";cin>>n;int *w=new int[n+1];int *bestx=new int[n+1];cout<<"please input weight:"<<endl;for(int i=1;i<=n;i++)cin>>w[i];int c;cout<<"please input limit weight:";cin>>c;clock_t start,end,over;start=clock();end=clock();over=end-start;start=clock();Maxloading(w,c,n,bestx);cout<<"The time is "<<((double)(end-start-over)/CLK_TCK)<<endl;system("pause");return 0;}。

实验五 箱子装载问题(分支限界法)

实验五  箱子装载问题(分支限界法)

实验五箱子装载问题一、实验目的:1、理解和复习所学各种算法的概念;2、掌握和复习所学各种算法的基本要素;3、掌握各种算法的优点和区别;4、通过应用范例掌握选择最佳算法的设计技巧与策略;二、实验内容及要求:1、使用贪心算法、回溯法、分支限界法解决箱子装载问题。

(任选两种)2、通过上机实验进行算法实现。

3、保存和打印出程序的运行结果,并结合程序进行分析,上交实验报告。

三、实验原理:回溯法原理:从开始结点出发,以深度优先方式搜索整个解空间。

这个节点成为活结点,同时也成为当前的扩展节点。

在当前的扩展节点处,搜索向纵深方向一致一个新节点。

贪心算法原理:贪心算法通过一系列的选择来得到问题的解。

他所做的每一个选择都是当前状态下局部最好选择,即贪心选择。

四、程序代码:贪心算法:#include<iostream>#include<stdlib.h>#define N 100using namespace std;int main(){int t[N],w0[N],w[N],n,c,m,i,j;int max=0,weight=0;bool tx[N];cout<<"请输入轮船的载重量c:"<<endl;cin>>c;cout<<"请输入可以装入的集装箱的数目n:"<<endl;cin>>n;cout<<"请输入各集装箱的重量w[i](1<=i<=n):"<<endl; for(int i=0;i<n;i++){cin>>w0[i];w[i+1]=w0[i];tx[i+1]=false;}for(i=1;i<n;i++){for(j=i+1;j<=n;j++){if(w[i]>w[j]) {int tem;tem=w[j];w[j]=w[i];w[i]=tem;}}}for(i=1;i<=n;i++)printf("%d ",w[i]);printf("n");for(i=1;i<=n;i++){int min=weight+w[i];if(min<=c){weight+=w[i];tx[i]=true;}}m=i-1;cout<<"最优装载情况为:"<<endl;cout<<"装入轮船的集装箱为:";max=0;for(i=1;i<=m;i++){if(tx[i]){max+=w[i];cout<<w[i]<<"--";}}cout<<endl;cout<<"装入的集装箱的最大重量为:"<<max<<endl;system("pause");}回溯法:#include<iostream>using namespace std;class Loading{friend float MaxLoading(float[],float,int);public:void Backtrack(int i);int n;int *x,*bestx;float *w,c,cw,bestw,r;};float Maxloading(float w1[],float c1,float c2,int n1,int bestx1[]) {Loading k;int j;float MAXLoad;k.x= new int [n1+1];k.bestx=bestx1;k.w = w1;k.c = c1;k.n = n1;k.cw = 0;k.bestw = 0;k.r = 0;for(int i=1;i<=n1;i++)k.r+=w1[i];k.Backtrack(1);delete [] k.x;cout<<"船1最优装载:"<<k.bestw<<endl;MAXLoad=k.bestw;for( j=1;j<=n1;j++){if(k.bestx[j]==0){MAXLoad+=w1[j];c2-=w1[j];if(c2<0){cout<<"找不到合理装载方案!"<<endl;return -1;}}}cout<<"船1中的箱子:";for( j=1;j<=n1;j++)if(k.bestx[j]==1)cout<<j<<" ";cout<<endl;cout<<"船2中的箱子:";for( j=1;j<=n1;j++)if(k.bestx[j]==0)cout<<j<<" ";cout<<endl;return MAXLoad;}void Loading::Backtrack(int i) {if(i>n){if(cw>bestw){for(int j=1;j<=n;j++)bestx[j]=x[j];bestw = cw;}return;}r-=w[i];if(cw+w[i]<=c){x[i]=1;cw+=w[i];Backtrack(i+1);cw-=w[i];}if(cw+r>bestw){x[i] = 0;Backtrack(i+1);}r+=w[i];}int main(){float w[20];float c1,c2,k;int n,bestx[20];cout<<"输入箱子数:";cin>>n;cout<<"输入箱子重量:";for(int i=1;i<=n;i++)cin>>w[i];cout<<"输入容量船1,船2:";cin>>c1>>c2;k=Maxloading(w,c1,c2,n,bestx);if(k!=-1)cout<<"总体最优装载:"<<k<<endl;return 1;}五、结果运行与分析:贪心算法:回溯法:六、心得与体会:通过本次实验,自己再次的联系了贪心算法和回溯法的应用,本次实验自己测试了很多次才成功,收获蛮大的,自己的编程能力进一步的提高了。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

算法分析与设计实验报告第八次附加实验
for(int i=1;i<n;i++)
cout<<bestx[i]<<",";
cout<<bestx[n]<<")"<<endl;
}
测试结果
当输入物品数量较少时:
当输入物品数量较一般时:
当输入物品数量较大时:
实验心得
最优装载就是求解载重量最好的载重方案,之前最优装载采用了贪心算法,这里使用的使分支限界法;其实在使用分支限界法进行了单源最短路径的
实现之后,在完成这个实验就显得更简单一点。

分支限界法的算法思想本身还
是很好理解的,但是在这个问题中由于涉及到了剪枝的问题,所以新加入了一
个0来判断一层是否结束,因为在一层结束的时候,代表该集装箱的情况已经
考虑完了,需要考虑下一个集装箱,这个时候就需要更新剩余集装箱的重量,
这会影响到一个右子树是否会被剪掉,因此要特别注意。

完整代码(分支限界法)
//分支限界法求最优装载
#include<iostream>
#include<time.h>
#include<iomanip>
#include<queue>
using namespace std;
class QNode
{
friend void Enqueue(queue<QNode *>&,int,int,int,int,QNode *,QNode *&,int *,bool);
friend void Maxloading(int *,int,int,int *);
private:
QNode *parent; //指向父节点的指针
bool LChild; //左儿子标志,用来表明自己是否为父节点的左儿子
int weight; //节点所相应的载重量
};
void Enqueue(queue<QNode *>&Q,int wt,int i,int n,int bestw,QNode
*E,QNode *&bestE,int bestx[],bool ch)
{
//将活节点加入到队列中
if(i==n) //到达叶子节点
{
if(wt==bestw) //确保当前解为最优解
{
bestE=E;
bestx[n]=ch;
}
return;
}
//当不为叶子节点时,加入到队列中,并更新载重、父节点等信息
QNode *b;
b=new QNode;
b->weight=wt;
b->parent=E;
b->LChild=ch;
Q.push(b);
}
void Maxloading(int w[],int c,int n,int bestx[]) //其中w[]为重量数组¦ { // c为船的总载重量,n为节点数
//初始化
queue <QNode *>Q; //活节点队列
Q.push(0); //将第一个节点加入队列中,并用0表示同层节点的尾部标志int i=1; //当前扩展节点的层数,此时为
int Ew=0; //扩展节点相应的载重量
int bestw=0; //当前最优载重量
int r=0; //剩余集装箱的重量
for(int j=2;j<=n;j++) //求得最初的剩余载重量
r+=w[j];
QNode *E =0; //当前扩展节点
QNode *bestE; //当前最优扩展节点
//搜索子集空间树
while(true)
{
//首先检查左儿子节点
int wt=Ew+w[i];
if(wt<=c) //左儿子节点为可行结点
{
if(wt>bestw)
bestw=wt;
Enqueue(Q,wt,i,n,bestw,E,bestE,bestx,true);//将左节点加入队列
}
//检查右儿子节点,利用上届函数
if(Ew+r>=bestw)
Enqueue(Q,Ew,i,n,bestw,E,bestE,bestx,false);//将右节点加入队列
E=Q.front(); //取出当前扩展节点
Q.pop();
if(!E) //到达同层的最末,此时需要更新剩余装箱载重量
{
if(Q.empty()) break; //此时队列为空
Q.push(0); //加入0,表示该层结束
E=Q.front();
Q.pop();
i++; //进入下一层
r-=w[i];//更新剩余集装箱的值
}
Ew=E->weight; //新扩展的节点对应的载重量
}
//构造当前最优解
for(int j=n-1;j>0;j--)
{
bestx[j]=bestE->LChild;
bestE=bestE->parent;
}
cout<<"最优载重量为:"<<bestw<<endl;
cout<<"最优载重方式:"<<"(";
for(int i=1;i<n;i++)
cout<<bestx[i]<<",";
cout<<bestx[n]<<")"<<endl;
}
int main()
{
int n;
cout<<"please input number of node:";
cin>>n;
int *w=new int[n+1];
int *bestx=new int[n+1];
cout<<"please input weight:"<<endl;
for(int i=1;i<=n;i++)
cin>>w[i];
int c;
cout<<"please input limit weight:";
cin>>c;
clock_t start,end,over;
start=clock();
end=clock();
over=end-start;
start=clock();
Maxloading(w,c,n,bestx);
cout<<"The time is "<<((double)(end-start-over)/CLK_TCK)<<endl;
system("pause");
return 0;
}。

相关文档
最新文档