分支界定法 branch-and-bound 分析与实现)(转载)
1. 介绍分支界定法之前需要了解一下广度优先搜索breadth-First-search(BFS)
宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
BFS,其英文全称是Breadth First Search。 BFS并不使用经验法则算法。从算法的观点,所有因为展开节点而得到的子节点都会被加进一个先进先出的队列中。一般的实验里,其邻居节点尚未被检验过的节点会被放置在一个被称为 open 的容器中(例如队列或是链表)list, vector或者是最优值的小根堆大根堆,而被检验过的节点则被放置在被称为 closed 的容器中。(open-closed表)
广度搜索的判断重复如果直接判断十分耗时,我们一般借助哈希表来优化时间复杂度。
分支界定法一般是广度优先搜索的优化
2. 分支界定法
分支界定算法是一种在问题的解空间树上搜索问题的解方法。一般如果有n层, 那么解空间树的叶节点有2 power n, 那么分支界定法就是使用限定条件,不断对这颗解空间树进行剪枝, 直到最后一层。
分支界定法采用广度优先或者最小耗费优先的方法搜索解空间树。 并且,在分解界定法中, 每一个活结点只有一次机会会成为扩展节点。他的搜索策略是:
1. 产生当前扩展节点的所有孩子节点, 并且在活结点链表中删除当前拓展节点;对于一般的求最优值和资源问题是二叉树, 对于求最短路径这样的图论问题, 是一般的树
2. 在产生的孩子节点中,剪掉那些不可能产生可行解(或最优解)的节点;(使用限定条件)
3.将其余所有的孩子节点加入活节点链表;
4.从活结点表中选择下一个活结点作为新的扩展节点;
5. 遇到层结束标记(采取不同的数据结构实现可能不同, 加入新的结束标记)
如此循环,直到找到问题的可行解(或最优解)或者活结点表为空。
分支界定法的思想是:首先确定目标值的上下界, 边搜索边减掉搜索树的某些枝, 提高搜索效率。
分支界定法在两个方面加速了算法的搜索效率, 一是在选择扩展节点时, 总是选择一个最小成本的节点, 尽可能早的进入最有可能成为最优解的分支;二是扩展节点的过程,舍弃导致不可行解或导致非最优解的子节点。
选择下一个扩展节点E-节点有如下方式
3. 使用C++实现FIFO的分支界定算法, 集装箱问题
现在有一个集装箱, 能装30的容量, 有分别为10, 15, 20的货物, 问如何能最大化集装箱的载重货物??
我们知道答案为30
下面使用C++实现改算法
#include <iostream>
#include <list> using namespace std;
#define MAX 3 const int CAP=;//最大容量
const int box[MAX]={,,};//三个箱子
int main()
{
int temp=,level=-,best=;
int curVal=,parentVal=,expectVal=;
list<int> queue;
queue.push_back(-);//-1表示一层
queue.push_back(parentVal);
do
{
parentVal=queue.front(); //first in first out
queue.pop_front(); //按照FIFO取出第一个元素,并且删除
if(parentVal!=-)
{
//left child
curVal=parentVal+box[level]; //提高效率的一方面
if(curVal>best&&curVal<=CAP)//边界条件 记录一个最大值 并且条件限定在CAP之内, 不满足条件的剪枝
{
best=curVal;
std::cout<<"bestvalue"<<best<<endl;
//最后一层节点不加入队列
if(level<MAX-)
{
queue.push_back(curVal);
}
} //right child
temp = ;
curVal=parentVal;
for(int i=level+;i<MAX;i++)
{
temp+=box[i];
}
expectVal=curVal+temp; //期望值为不加上当前level的值, 剩下的可能最大的值,提高效率的第二个方面
std::cout<<"expect : "<<expectVal<<endl;
//预计最大值若大于目前最佳值,则加入队列;否则不加入,即剪枝
if(expectVal>best&&level<MAX-)
{
queue.push_back(curVal);
}
for(list<int>::iterator ite = queue.begin(); ite != queue.end(); ite++)
{
std::cout<<" "<<*ite;
} }
else//处理层次问题,加入层结束标志,进入下一层
{
if(level<MAX-)
{
queue.push_back(-);
}
level++;
} }while(level!=MAX&&queue.empty()!=true);//到最后一层或者是队列为空结束 std::cout<<best<<endl;
system("pause");
return ;
}
如果细分,上面的算法实际上是FIFO通过加入“限界”策略加速搜索。
4. FIFO实现分支搜索
w1+w2+……+wn≤c1+c2。
确定是否有一种可将所有n 个货箱全部装船的方法。若有的话,找出该方法。
1) 使用FIFO分支搜索实现算法
#include <iostream>
#include <queue>
using namespace std;
int w[];
int n;
int bestw=;
queue<int> queue1;//存储当前或节点
void AddLiveNode(int wt,int i)
{
if (i==n)//是叶子, 需要结束
{
if (wt>bestw)
bestw=wt;
}
else //不是叶子
{
queue1.push(wt);
}
} int MaxLoading(int c)
{
// 初始化活结点队列,标记分层
queue1.push(-);
int level=;
int currentw=;
while(!queue1.empty())
{
if(currentw!= -)
{
if(currentw+w[level]<=c) //左节点,限定条件为current + wi < c1
{
AddLiveNode(currentw+w[level],level); //物品i可以装载
}
AddLiveNode(currentw,level); //右孩子总是可行的,不装载物品i
//取下一个E-结点
currentw = queue1.front();
queue1.pop();
cout<<"current"<<currentw<<endl;
}
else //到达层的尾部
{
if (queue1.empty())
{
cout<<"best"<<bestw<<endl;
return bestw;
}
//添加分层标记
queue1.push(-);
//取下一个E-结点
currentw = queue1.front();
queue1.pop();
cout<<"current next level"<<currentw<<endl;
level++;
} //ew的
}
} void main( )
{
int c1,c2;int sum=;
scanf("%d", &c1);
scanf("%d", &c2);
scanf("%d", &n);
cout<<"n"<<n<<endl;
for(int i=;i<n;i++)
{
scanf("%d", w+i);
sum=sum+w[i];
}
if (sum<=c1 || sum<=c2)
{
cout<<"need only one ship"<<endl;
return;
}
if (sum>c1+c2)
{
cout<<"no solution"<<endl;
return;
}
MaxLoading(c1);
if ((sum-bestw) <= c2)
{
cout<<"The first ship loading"<<bestw<<endl;
cout<<"The second ship loading"<< sum-bestw<<endl;
}
else
{
cout<<"no solution"<<endl;
}
system("pause");
}
5. 优先队列构造最优解
数据结构设计:
1)要输出解的方案,在搜索过程中仍需要生成解结构树,其结点信息包括指向父结点的指针和标识物品取舍(或是父结点的左、右孩子)。 (左节点1, 右节点0)
2)堆结点包括结点优先级信息:结点所在分支的装载上界uweight;堆中无法体现结点的层次信息(level),只能存储在结点中;
AddLiveNode用于把活结点加到子树中,并把HeapNode类型的活结点插入最大堆。
3)不同于算法2,由于扩展结点不是按层进行的,计算结点所在分支的装载上界时(expectVal>best),要用数组变量r记录当前层以下的最大重量,这样可随时方便使用各层结点的装载上界。
6. 算法复杂度
不管如何算法的复杂度仍为O(2n),但通过限界策略,并没有搜索子集树中的所有结点,且由于每次都是选取最接近最优解的结点扩展,所以一旦搜索到叶结点作E结点时算法就可结束。算法结束时堆并不一定为空。
转载自:http://blog.csdn.net/yinlili2010/article/details/39313035
分支界定法 branch-and-bound 分析与实现)(转载)的更多相关文章
- 干货 | 10分钟搞懂branch and bound(分支定界)算法的代码实现附带java代码
Outline 前言 Example-1 Example-2 运行说明 00 前言 前面一篇文章我们讲了branch and bound算法的相关概念.可能大家对精确算法实现的印象大概只有一个,调用求 ...
- 干货 | 10分钟带你全面掌握branch and bound(分支定界)算法-概念篇
00 前言 之前一直做启发式算法,最近突然对精确算法感兴趣了.但是这玩意儿说实话是真的难,刚好boss又叫我学学column generation求解VRP相关的内容.一看里面有好多知识需要重新把握, ...
- Branch and Bound:分支限界算法
http://blog.sciencenet.cn/blog-509534-728984.html 分支定界 (branch and bound) 算法是一种在问题的解空间树上搜索问题的解的方法.但与 ...
- Python 实现整数线性规划:分枝定界法(Branch and Bound)
今天做作业,要实现整数线性规划的分枝定界法算法.找了一些网上的博客,发现都很屎,感觉自己写的这个比较清楚.规范,所以在此记录.如有错误,请指正. from scipy.optimize import ...
- 管理分支:git branch
新建分支的意义: 创建一个单独的工作分支,避免对主分支master造成太多的干扰,也方便与他们交流协作. 进行高风险的工作时,创建一个实验性的分支,扔掉一个烂摊子总比收拾一个烂摊子好得多. 合并别人工 ...
- git pull时解决分支分叉(branch diverged)问题
git pull时出现分支冲突(branch diverged) $ git status # On branch feature/worker-interface # Your branch and ...
- git 使用详解(8)—— 分支HEAD、branch/checkout
有人把 Git 的分支模型称为"必杀技特性",而正是因为它,将 Git 从版本控制系统家族里区分出来.Git 有何特别之处呢?Git 的分支可谓是难以置信的轻量级,它的新建操作几乎 ...
- Git裸仓库的分支(Active Branch)切换
Git裸仓库的Active Branch切换方法 在服务器上通过init --bare创建了一个裸仓库作为远程仓库使用,并且存在三个分支(master/kid/develop),但在使用中发现代码虽然 ...
- 分支预测(branch prediction)
记录一个在StackOverflow上看到一个十分有趣的问题:问题. 高票答案的优化方法: 首先找到罪魁祸首: if (data[c] >= 128) sum += data[c]; 优化方案使 ...
随机推荐
- [Mongodb] Relica Set复制集集群简单搭建--持续更新
这里我们搭建一个没有访问控制,奇数个Set没有仲裁者的集群 1.三个配置文件添加 replication.replSetName:"Replica_test" 并启动三个实例2.连 ...
- 使用compass编译sass
1.初始化项目 compass create test(项目名称),会在当前目录下创建test子目录,test的子目录下有config.gb文件,sass和stylesheets文件夹. 2.编写sa ...
- QQ右下角浮动窗口
<html><head><meta http-equiv="Content-Type" content="text/html; charse ...
- Request.ServerVariables
APPL_MD_PATH-->APPL_PHYSICAL_PATH-->C:\Users\TomZhang\Desktop\GAP\后台修改\UMS\UMSSite\AUTH_TYPE-- ...
- [POJ2151]Check the difficulty of problems (概率dp)
题目链接:http://poj.org/problem?id=2151 题目大意:有M个题目,T支队伍,第i个队伍做出第j个题目的概率为Pij,问每个队伍都至少做出1个题并且至少有一个队伍做出N题的概 ...
- XE7 & IOS开发之开发账号(1):开发证书、AppID、设备、开发授权profile的申请使用,附Debug真机调试演示(XCode所有版本通用,有图有真相)
网上能找到的关于Delphi XE系列的移动开发的相关文章甚少,本文尽量以详细的图文内容.傻瓜式的表达来告诉你想要的答案. 原创作品,请尊重作者劳动成果,转载请注明出处!!! 注意,以下讨论都是以&q ...
- 火车采集器 帝国CMS7.2免登录发布模块
帝国cms7.2增加了金刚模式,登录发布有难度.免登录发布模块配合火车采集器,完美解决你遇到的问题. 免登录直接获取栏目列表 通过文件内设置密码免登录发布数据 帝国cms7.2免登陆文章发布接口使用说 ...
- 规则引擎集成接口(四)SQL执行语句
SQL执行语句 右键点击数据库连接文件“hr”—“添加SQL执行语句”,如下图: 弹出窗体,如下图: 将显示名称改为“部门名称”,返回至类型设置为“string”,在编写sql语句,如下图: 点击确定 ...
- Struts2:效验器——注解
效验器三类: 编程式——Java代码 声明式——xml 注释法——@ 注解验证可以修饰属性的getter方法,也可以修饰执行方法Action中校验失败时,返回input逻辑视图 struts.xml ...
- 使用微软CORS包不能跨域访问的问题
使用jquery的ajax异步调用的时候会出现不能跨域访问的问题,这个问题一般有两种方法. 1:使用jsonp跨域 2:使用html5的CORS 在这里只谈论第二种,微软对CORS提供的了支持,在Nu ...