热门标签 | HotTags
当前位置:  开发笔记 > 人工智能 > 正文

算法详解之分支限界法的具体实现

这篇文章主要介绍了算法详解之分支限界法的具体实现,需要的朋友可以参考下

首先我们来关注一个问题:

问题描述:

布线问题:印刷电路板将布线区域划分成n×m个方格阵列,要求确定连接方格阵列中的方格a的中点到方格b的中点的最短布线方案。在布线时,电路只能沿直线或直角布线,为了避免线路相交,已布了线的方格做了封锁标记,其他线路不允许穿过被封锁的方格。如下图所示:

 

算法思路:

布线问题的解空间是一个图,则从起始位置a开始将它作为第一个扩展结点。与该扩展结点相邻并可达的方格成为可行结点被加入到活结点队列中,并且将这些方格标记为1,即从起始方格a到这些方格的距离为1。接着,从活结点队列中取出队首结点作为下一个扩展结点,并将与当前扩展结点相邻且未标记过的方格标记为2,并存入活结点队列。这个过程一直继续到算法搜索到目标方格b或活结点队列为空时为止。

在实现上述算法时,

(1) 定义一个表示电路板上方格位置的类Position。

它的2个成员row和col分别表示方格所在的行和列。在方格处,布线可沿右、下、左、上4个方向进行。沿这4个方向的移动分别记为0,1,2,3。下表中,offset[i].row和offset[i].col(i= 0,1,2,3)分别给出沿这4个方向前进1步相对于当前方格的相对位移。

(2) 用二维数组grid表示所给的方格阵列。

初始时,grid[i][j] = 0, 表示该方格允许布线,而grid[i][j] = 1表示该方格被封锁,不允许布线。

算法图解:

代码贴出来:

代码如下:

#include
typedef struct {
  int row;
  int col;
}Position;
int FindPath (Position start, Position finish, int &PathLen, Position *&path)
{ //计算从起始位置start到目标位置finish的最短布线路径,找到返回1,否则,返回0
  int  i;
  if ((start.row = = finish.row) && (start.col = = finish.col)) {
PathLen = 0;   return 0; } //start = finish
  //设置方格阵列”围墙”
  for (i = 0; i <= m+1; i++)
grid[0][i] = grid[n+1][i] = 1; //顶部和底部
  for (i = 0; i <= n+1; i++)
grid[i][0] = grid[i][m+1] = 1; //左翼和右翼
  //初始化相对位移
int  NumOfNbrs = 4; //相邻方格数
  Position offset[4], here, nbr;
  offset[0].row = 0;   offset[0].col = 1;   //右
  offset[0].row = 1;   offset[0].col = 0;   //下
  offset[0].row = 0;   offset[0].col = -1;  //左
  offset[0].row = -1;  offset[0].row = 0;  //上
  here.row = start.row;
  here.col = start.col;
  LinkedQueue Q; //标记可达方格位置
  do {
for (i = 0; inbr.row = here.row + offset[i].row ;
nbr.col = here.col + offset[i].col;
if (grid[nbr.row][nbr.col] = = 0) { //该方格未标记
  grid[nbr.row][nbr.col] = grid[here.row][here.col] + 1;
if ((nbr.row = = finish.row) && (nbr.col = = finish.col))  break;//完成布线
Q.Add(nbr); 
       }
}
if ((nbr.row = = finishi.row) && (nbr.col = = finish.col))  break;//完成布线
if (Q.IsEmpty()) //活队列是否为空
return 0; //无解
      Q.delete(here); //取下一个扩展结点
}while (1);
//构造最短布线路径
PathLen = grid[finish.row][finish.col] - 2;
path = new Position[PathLen];
here = finish;
for (int j = PathLen – 1; j >= 0; j--) { //找前驱位置
  path[j] = here;
  for (i = 0; inbr.row = here.row + offset[i].row ;
nbr.col = here.col + offset[i].col;
if (grid[nbr.row][nbr.col] = = j+2)  break;
}
  here = nbr; //向前移动
  }
return 1;
}
void main ()
{
  int grid[8][8];
  int PathLen, *path;
  Position start, finish;
  start.row = 3;  start.col = 2;
  finish.row = 4; finish.col = 6;


  FindPath (start, finish, PathLen, path);
 }

代码贴出来:

代码如下:

#include
typedef struct {
  int row;
  int col;
}Position;
int FindPath (Position start, Position finish, int &PathLen, Position *&path)
{ //计算从起始位置start到目标位置finish的最短布线路径,找到返回1,否则,返回0
  int  i;
  if ((start.row = = finish.row) && (start.col = = finish.col)) {
PathLen = 0;   return 0; } //start = finish
  //设置方格阵列”围墙”
  for (i = 0; i <= m+1; i++)
grid[0][i] = grid[n+1][i] = 1; //顶部和底部
  for (i = 0; i <= n+1; i++)
grid[i][0] = grid[i][m+1] = 1; //左翼和右翼
  //初始化相对位移
int  NumOfNbrs = 4; //相邻方格数
  Position offset[4], here, nbr;
  offset[0].row = 0;   offset[0].col = 1;   //右
  offset[0].row = 1;   offset[0].col = 0;   //下
  offset[0].row = 0;   offset[0].col = -1;  //左
  offset[0].row = -1;  offset[0].row = 0;  //上
  here.row = start.row;
  here.col = start.col;
  LinkedQueue Q; //标记可达方格位置
  do {
for (i = 0; inbr.row = here.row + offset[i].row ;
nbr.col = here.col + offset[i].col;
if (grid[nbr.row][nbr.col] = = 0) { //该方格未标记
  grid[nbr.row][nbr.col] = grid[here.row][here.col] + 1;
if ((nbr.row = = finish.row) && (nbr.col = = finish.col))  break;//完成布线
Q.Add(nbr); 
       }
}
if ((nbr.row = = finishi.row) && (nbr.col = = finish.col))  break;//完成布线
if (Q.IsEmpty()) //活队列是否为空
return 0; //无解
      Q.delete(here); //取下一个扩展结点
}while (1);
//构造最短布线路径
PathLen = grid[finish.row][finish.col] - 2;
path = new Position[PathLen];
here = finish;
for (int j = PathLen – 1; j >= 0; j--) { //找前驱位置
  path[j] = here;
  for (i = 0; inbr.row = here.row + offset[i].row ;
nbr.col = here.col + offset[i].col;
if (grid[nbr.row][nbr.col] = = j+2)  break;
}
  here = nbr; //向前移动
  }
return 1;
}
void main ()
{
  int grid[8][8];
  int PathLen, *path;
  Position start, finish;
  start.row = 3;  start.col = 2;
  finish.row = 4; finish.col = 6;


  FindPath (start, finish, PathLen, path);
 }


好了,问题解出来了。咦,我们用的是什么方法呢?呵呵,对,这就是分支限界算法。


算法总结:

分支限界法基本思想:

&#8226; 分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。

&#8226; 在分支限界法中,每一个活结点只有一次机会成为扩展结点。活结点一旦成为扩展结点,就一次性产生其所有儿子结点。

&#8226; 在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。

&#8226; 此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。这个过程一直持续到找到所需的解或活结点表为空时为止。

分支限界法与回溯法的不同:

(1)求解目标不同:回溯法的求解目标是找出解空间树中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出在某种意义下的最优解。

(2)搜索方式的不同:回溯法以深度优先的方式搜索解空间树,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树。


推荐阅读
  • 自动驾驶技术中的数据标注应用 | 曼孚科技
    本文探讨了数据标注在自动驾驶领域的具体应用,包括多种标注类型及其重要性。 ... [详细]
  • 数字中心在厦门大数据安全开放创新应用大赛中荣获交通专题算法赛一等奖
    数字中心的数据应用分析团队在“厦门大数据安全开放创新应用大赛·交通专题”中荣获算法赛一等奖。 ... [详细]
  • CM 创始人分享:在 GitHub 上成为开源项目的守护者
    本文由 CM 创始人 Steve Klabnik 发表在其个人博客上,详细介绍了他在 GitHub 上为 Rails 开源项目所做的贡献和经验,特别强调了如何有效管理和筛选项目中的问题。 ... [详细]
  • 基于Linux开源VOIP系统LinPhone[四]
    ****************************************************************************************** ... [详细]
  • Java swing 连连看小游戏  开发小系统 项目源代码 实训实验毕设
    Javaswing连连看小游戏开发小系统项目源代码实训实验能满足学习和二次开发可以作为初学者熟悉Java的学习,作为老师阶段性学习的一个成功检验不再是单调的理解老师空泛的知识,导入 ... [详细]
  • 插入排序_动画 | 什么是插入排序? ... [详细]
  • 本文将详细介绍如何在Mac上安装Jupyter Notebook,并提供一些常见的问题解决方法。通过这些步骤,您将能够顺利地在Mac上运行Jupyter Notebook。 ... [详细]
  • 在2019中国国际智能产业博览会上,百度董事长兼CEO李彦宏强调,人工智能应务实推进其在各行业的应用。随后,在“ABC SUMMIT 2019百度云智峰会”上,百度展示了通过“云+AI”推动AI工业化和产业智能化的最新成果。 ... [详细]
  • 全面解析二叉树与递归算法:基于LeetCode实战案例(题目编号114、297、449、1008、450)
    递归作为一种强大的问题求解工具,在程序设计中占据着重要地位。它不仅能够帮助编写简洁明了的代码,还能显著提升程序的整体质量。在解决复杂问题时,递归函数的应用尤为广泛,如深度优先搜索(DFS)、回溯算法和动态规划等。本文通过LeetCode上的经典题目(编号114、297、449、1008、450),详细解析了二叉树与递归算法的结合应用,为读者提供了丰富的实战案例和深入的技术分析。 ... [详细]
  • 看到成绩时,离散数学得了94分,本以为一切顺利,却没想到多媒体课程只有57分,四年的奖学金梦想也因此破灭。有没有曾经挂过科但后来依然取得好成就的同学?现在心情非常低落,希望能得到一些安慰和建议。虽然挂科有些遗憾,但至少以后不用再上那些乏味的课程了,而且评优的机会也与我无关了。 ... [详细]
  • 20款必备PS插件免费大放送,附详细安装指南
    对于众多关注小资源并学习PS的用户来说,每次分享设计素材都会收到大量反馈。为了更好地满足大家的需求,今天我们特别推出了20款必备的PS插件大合集,并附有详细的安装指南,确保每位用户都能轻松上手,提升设计效率。 ... [详细]
  • 近期在研究逆向工程,因此尝试了一些CTF题目。通过合天网络安全实验室的CTF实战演练平台(http://www.hetianlab.com/CTFrace.html),我对Linux逆向工程的掌握还不够深入,因此暂时跳过了RE300题目。首先从逆向100开始,将文件后缀名修改为.apk进行初步分析。这一过程不仅帮助我熟悉了基本的逆向技巧,还加深了对Android应用结构的理解。 ... [详细]
  • 优化后的标题:Apache Cassandra数据写入操作详解
    本文详细解析了 Apache Cassandra 中的数据写入操作,重点介绍了 INSERT 命令的使用方法。该命令主要用于将数据插入到指定表的列中,其基本语法为 `INSERT INTO 表名 (列1, 列2, ...) VALUES (值1, 值2, ...)`。通过具体的示例和应用场景,文章深入探讨了如何高效地执行数据写入操作,以提升系统的性能和可靠性。 ... [详细]
  • 如何在Linux服务器上配置MySQL和Tomcat的开机自动启动
    在Linux服务器上部署Web项目时,通常需要确保MySQL和Tomcat服务能够随系统启动而自动运行。本文将详细介绍如何在Linux环境中配置MySQL和Tomcat的开机自启动,以确保服务的稳定性和可靠性。通过合理的配置,可以有效避免因服务未启动而导致的项目故障。 ... [详细]
  • 本文探讨了POJ3177中的冗余路径问题,并详细介绍了如何利用Tarjan算法进行求解。通过分析图的强连通分量,Tarjan算法能够高效地识别出图中的关键路径和冗余路径,为解决复杂网络问题提供了有力工具。此外,文章还结合具体实例,深入讲解了算法的应用步骤和实现细节,帮助读者更好地理解和掌握这一重要算法。 ... [详细]
author-avatar
隐之王语录
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有