【算法】分枝限界法:广度优先搜索(0-1背包问题&迷宫问题)

C++ 算法篇 广度(宽度)优先搜索(BFS) 广度优先遍历 广度优先遍历(Breadth_First_Search),又称为广度优先搜索,简称BFS。 图的BFS类似于树的层序遍历。 广度优先遍历 如图将左边的图变形,得到右边的图,然后一层一层的遍历。 这里借助一个队列来实现一层一层的遍历。 邻接矩阵的BFS 核心代码 /** * 邻接矩阵的广度优先遍历算法 */ void BFSTraverse(MGraph G){... 阅读详情
AI摘要

文章详细介绍了分枝限界法的设计思想,包括定义、策略,以及与回溯法的异同。核心步骤包括设计解空间结构、限界函数和广度优先搜索,并通过实例分析了(0-1)背包问题和迷宫问题的解决方案。通过限界函数和广度优先搜索,能在解空间中高效寻找最优解。

目录

1 设计思想

1.1 定义

1.2 策略

1.3 分枝限界法与回溯法的异同

 2 设计步骤

2.1 关键问题解决

2.2 求目标函数最大值问题的算法描述

3 时空性能分析

3.1 时间性能

3.2 空间性能 

4 应用

4.1 (0-1)背包问题

4.2 迷宫问题


如果看完觉得这篇文章对你有帮助的话,请点个赞支持一下~ 

1 设计思想

1.1 定义

  • 以广度优先方式搜索解空间树,并结合限界函数提高搜索效率。
  • 求解目标:找出满足约束条件的一个解,或在满足约束条件的解中选取某种意义上的最优解。

1.2 策略

采用广度优先的策略,依次生成所有子节点。
① 设计一个限界函数,计算各节点的值,把符合限界条件的节点放入活节点表HT中。使用队列或优先队列,先进先出。
​​     当可行解不止一个时,为衡量这些可行解的优劣,需要通过目标函数来进行评价。
② 对于待处理的节点,根据限界函数估算目标函数的可能取值,从中选取使目标函数取得极值(极大或极小)的节点进行广度优先搜索。
也就是说,每次都选择“最有利”的一个子节点作为优先扩展节点,一次性将这个节点的子节点全部展开,然后继续根据步骤①②对新展开的子节点进行选取。
③ 使搜索朝着解空间树上有最优解的方向前进,由此尽快找到问题的解。

分支限界法节点展开图

1.3 分枝限界法与回溯法的异同

  • 相同点:都在问题的解空间树中搜索问题的解
  • 不同点:

 2 设计步骤

  1. 确定解空间结构:定义问题的解空间,确定易于搜索的解空间结构。
  2. 设计限界函数:确定目标函数值的估算方法。(关键)
  3. 广度优先搜索:根据限界函数,以广度优先方式搜索解空间树,避免无效搜索,从而得到最优解。

2.1 关键问题解决

  •  设计合适的限界函数:
    ① 估算目标函数值,选取“最有利”的一个子节点作为扩展节点并删除不必要的子节点,简化搜索。要求计算简单、保证最优解在搜索空间中、在搜索早期对不合条件的进行剪枝。
    ② 方法:具体分析
         a.目标函数求最大值:设计估算目标函数上界的限界函数 ub(s_{i})。通常根节点的ub≥最优解的ub。若 s_{i} 是 s_{j} 的父节点,则 ub(s_{i})\geqslant ub(s_{j}) 。
         得到一个可行解的ub(s_{k})后,将所有小于 ub(s_{k}) 的节点剪枝。

         b.目标函数求最小值:设计估算目标函数下界的限界函数 lb(s_{i})。通常根节点的lb≥最优解的lb。若 s_{i} 是 s_{j} 的父节点,则 lb(s_{i})\leqslant lb(s_{j}) 。
         得到一个可行解的lb(s_{k})后,将所有大于 lb(s_{k}) 的节点剪枝。
  •  组织活节点表:
    用于存放满足限界条件的节点。不同组织方式对应不同搜索方式。
    ① 队列式:将活节点表组织成队列,按照先进先出原则取下一个扩展节点。
    ② 优先队列式:将活节点表组织成优先队列,按优先队列排序后的优先级选取下一个扩展节点。可选择小根堆or大根堆。
  • 确定最优解向量:
    因为节点处理是跳跃式的,因此搜索到某个叶子节点且对应一个最优解,采用以下两种方式求最优解的各个分量:
    ① 对每个扩展结点保存从根节点到该节点的路径:比较浪费空间,但实现简单,较常用。
    ② 在搜索过程中构建搜索经过的树结构:需要给每个节点增加一个指向父节点的指针,当找到最优值时,通过该指针找到对应的最优解向量。

Q:学习过程中的疑惑:为什么广度优先搜索之后的结果就是最优解?

因为广度优先搜索是每搜索到一个节点就扩展它的全部子节点,也就是说,广度优先搜索方法是一层一层依次搜索的。这样的话,只要到达叶子节点,搜索结束,所得到的层数就是最小的,即路径是最短的。

换句话说,如果在搜索过程中已经找到了终点,那么此时的路径一定是从起点开始的最优路径。因为如果路径不是最优路径,那么一定有其他路径更早到达叶子节点,也就比此时已经搜索到的路径更短。

2.2 求目标函数最大值问题的算法描述

3 时空性能分析

3.1 时间性能

  • 最坏情况下,时间复杂度是指数级。
  • 采用限界函数,大范围剪枝,同时根据限界函数不断调整搜索方向,加快了问题的求解速度。

3.2 空间性能 

  • 为了得到最优解,每个扩展节点保存该节点到根的路径,或构建搜索树,因此需要额外存储空间。
  • 需要维护待处理节点表HT(通常为优先队列)。
  • 最坏情况下,空间复杂度是指数级。

4 应用

4.1 (0-1)背包问题

(内容来源于课堂课件)

 1. 队列式分枝限界法  

 2. 优先队列式分枝限界法  

 3. 对比  

 *** 算法伪代码描述及优化 *** 

 

 4. 算法分析  

4.2 迷宫问题

1.问题描述

定义一个二维数组,例如:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

输入格式:
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一最短路径。

输出格式:
左上角到右下角的最短路径,格式如样例所示。

输入样例:
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

输出样例:
(0,0) (1,0) (2,0) (2,1) (2,2) (2,3) (2,4) (3,4) (4,4)

2.实现步骤:
(1)从入口开始,判断它的上下左右的邻边元素是否满足条件,如果满足条件就引入队列。此处用了一个 R[4][2]的二维数组,用途是可以直接在四次代码循环内,完成用父节点的x,y计算上下左右四个节点的下标,而不用多次写重复的判断代码。用循环代替了分支结构,使代码更加简洁清晰。
(2)取队首元素并将这个元素出队。寻找其相邻且未被访问的元素(用visited数组标记),满足条件的,将其进入队列并标记元素的前驱节点为队首元素。
(3)重复步骤(2),直到队列为空(没有找到可行路径)或者找到了终点。最后从终点开始,根据节点的前驱节点找出一条最短的可行路径。

其中,前驱节点使用类指针标记,最后通过终点的地址一步步往前追溯,得到完整的路径。

参考代码:

using namespace std;
#include <iostream>
#include <queue>
#include <stack>
#define MAX 10
int maze[MAX][MAX];
bool visited[MAX][MAX]; //记录节点是否被访问过


class Point {
public:
    int x;//行
    int y;//列
    int t; //到这个点所花费的总路程
    Point* before; //指向父状态,用于逆向寻找路径
};
int R[4][2] = {
    -1,0,
    1,0,
    0,-1,
    0,1
};//用于状态扩展(上下左右)

Point* BFS() { //返回终点状态
    queue<Point*> q;
    int x = 0, y = 0, t = 0;
    Point* start = new Point(); //函数内部定义的对象,要用new运算符分配空间
    起点初始化
    start->x = 0;
    start->y = 0;
    start->t = 0;
    start->before = NULL;//起点没有父状态
    q.push(start); //起点入队
    while (!q.empty()) {
        Point* tmp = q.front(); //【新建指针指向队头】
        q.pop(); //取出一个节点进行扩展
        for (int i = 0; i < 4; i++) {//遍历四种状态(上下左右)
            x = tmp->x + R[i][0];
            y = tmp->y + R[i][1];
            【skip三连!不满足条件的全部杀杀杀】
            if (x < 0 || x > 4 || y < 0 || y > 4) continue; //数组越界,跳过
            if (visited[x][y]) continue; //访问过,跳过
            if (maze[x][y] == 1) continue; //是墙,跳过
            【可行的,新建节点并入队】
            Point* newtmp = new Point();
            newtmp->x = x;
            newtmp->y = y;
            newtmp->t = tmp->t + 1; //路程为父节点+1
            newtmp->before = tmp; //父节点为tmp
            if (x == 4 && y == 4) return newtmp;//到达终点,则返回终点节点指针
            q.push(newtmp); //新节点入队
            visited[x][y] = true;
        }
        //【结束一轮循环后,一个节点的上下左右都扩展完毕,继续检索子节点】
    }
    return start;
}
int main()
{
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            cin >> maze[i][j];
            visited[i][j] = false;
        }
    }
    Point* p = BFS();
    stack<Point*> s;
    //将节点从终点开始入栈,然后按出栈顺序输出,则可得到正序的路径
    while (p != NULL) {
        s.push(p);
        p = p->before;
    }
    while (!s.empty()) {
        Point* tmp = s.top();
        s.pop(); //得到节点信息,并出栈
        cout << "(" << tmp->x << "," << tmp->y << ")" << endl;
    }
}

如果看完觉得这篇文章对你有帮助的话,请点个赞支持一下~ 

广度优先搜索(BFS)(算法笔记) 深度优先搜索是一种枚举所有完整路径以遍历所有情况的搜索方法,总是以“广度”作为前进的关键词,采用队列实现。广度优先搜索属于搜索问题的一种,当问题可以被描述为“路径搜索”时,就可以采用搜素问题的所有解的方式来进行解决,所以BFS本质还是暴力。广搜也存在“岔道口”,只是当遇到“岔道口”时,需要将本层所有的岔道都走一遍,然后再走下一层的岔道,符合队列的“先进先出”思想。广搜和深搜的共同点之一是只有一个起点,也就是说一次搜索只能遍历以一个点为起点的所有路径。而BFS更适合需要搜索最优解的问题, 阅读详情

相关推荐

广度优先搜索(BFS)

广度优先搜索(Breadth First Search)又名宽度优先搜索,是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。图1 广度优先搜索广度优先搜索适合找最优解,如图1所示:1就是从0到1;2就是从0到2;

Hacket_Xu的博客 3696

广度优先搜索(BFS)

/ 定义图的边结构// 与边相连的另一顶点的索引Edge* next;// 指向下一条邻接边的指针} Edge;// 定义图的顶点结构// 顶点数据// 指向第一个邻接边的指针} Vertex;// 定义图的邻接表结构// 图中顶点的数量// 存储顶点的数组} Graph;

m0_68805093的博客 1万+

DeepSeek+Coze扣子搭建智能体(保姆级教程)

DeepSeek+Coze扣子搭建智能体(保姆级教程)

yizhen91y的博客 1万+

广度优先搜索(BFS)详解

广度优先搜索(BFS)是一种用于图形数据结构的遍历算法,它从给定的起始顶点开始,以广度优先的方式逐层搜索图中的节点,直到找到目标节点或遍历完整个图。BFS算法通常使用队列数据结构来实现,它的时间复杂度为O(V+E),其中V表示图中顶点数,E表示边数。BFS算法在求解最短路径、连通性、拓扑排序等问题中具有重要应用。广度优先搜索(Breadth First Search),简称广搜(BFS)。广搜是逐层扩展状态的搜索策略,常用于解决连通性问题和最短路问题。

m0_69596371的博客 6107

systermverilog中for循环中的fork join执行情况分析

仅为本人学习记录,如有错误感谢指正!

qq_63807221的博客 1461

晶圆测试厂wafer map管理建议

按照Recipe设定bin定义 应有版本管理概念,一般使用最新版本做为活动版本即可 Bin明细中应包含 BinID、BinCode、BinName、BinType、BinColor、Description BinID可使用数字类型 BinCode可参照实际机台的Bin,用于匹配 有些公司也将BinID、BinCode理解为SBin和HBin 即 Software Bin &amp; Hardware Bin 一般也将BinID对应到客户的Bin BinType

凯神做开发 1万+

回溯法、分枝限定法--求解迷宫最近距离

在一个游戏中,玩家处于一个如下所示12行12列的迷宫: 0,1,0,0,0,1,1,1,0,1,0,1 0,0,0,1,0,0,0,0,1,0,0,1 0,1,0,1,0,1,1,1,0,1,0,0 0,1,0,0,0,0,0,1,0,0,1,1 0,0,0,0,1,0,0,0,0,0,0,0 0,0,1,0,0,0,1,0,0,0,1,0 0,0,1,0,0,0,0,0,1,0,0,0 1,0,0,1,0,1,0,0,0,1,0,1 0,0,1,0,1,0,1,0,1,0,0,0 0,0,0,0,0,1.

qq_48566899的博客 655

软件测试--用例篇(测试用例的好处、测试用例的七种设计方法、测试用例的粒度、测试用例的评价)

作为软件测试工程师,最主要的工作就是:编写测试用例,那么为什么要编写测试用例?它有什么好处?如何编写测试用例?测试用例写简单好还是复杂好?如何评价测试用例的质量? 天呐撸!能说不会吗?! 作为倾向软件测试工程师的老铁们,还是一起来学习吧! 一、编写测试用例的好处 测试用例是测试者的依据 测试用例使得工作可重复,是自动化测试的基础 补充:自动化测试的前提条件是:功能比较稳定,页面...

cherrydreamsover的博客 3734

分支限界法_迷宫问题

写这道题的时候知道是用bfs(广度优先),基本框架也写了出来,但是不知道怎么保存路径。搜了一下,看了一下别人的,但是实在没看下去。可能是感觉重要地方没有注释,代码耦合性也有点高(也可能没有,反正就是没看下去,我自己问题吧,没沉下心看)最后只能问gpt,让gpt帮我完善一下,然后就知道了保存前驱结点这一个方法,真的是豁然开朗。(这个方法也不是不知道,但还是练的太少)

weixin_72824346的博客 390

LangGraph-StateGraph 和 Graph API 源码分析

摘要: StateGraph是LangGraph的核心API,用于构建有状态工作流图。本文分析了其实现原理,包括: 核心类关系:StateGraph(构建器)和CompiledStateGraph(继承自Pregel的可执行图) 关键流程:状态模式到通道的映射、节点到PregelNode的转换 实现特点: 支持TypedDict和Pydantic两种状态模式 自动选择通道类型(LastValue或BinaryOperatorAggregate) 通过映射函数处理节点输入输出 边实现基于通道写入机制 编译过程

838

Cadence OrCAD Capture CIS元器件管理时ERROR(ORCIS-6454): Temporary part number tracking is turned on报错的解决方法

使用Part manager对工程的元器件进行批量管理时,出现如下图所示的ERROR(ORCIS-6454): Temporary part number tracking is turned on报错其解决方法如下。

fydar的博客 3501

算法入门7:分支限界法

https://blog.youkuaiyun.com/jarvischu/article/details/16940337上一篇回溯法中已经提到过,回溯法的思想是深度优先搜索加剪枝,与之相对,分支限界法的思想是广度优先搜索加剪枝。1. 分支限界法 – 广度优先搜素                                         1. 简单概述分支限界法思路的简单描述是:把问题的解空间转化成了...

EminentBoy的博客 950

三极管电平转换电路

摘要:本文介绍了三种基于三极管的电平转换电路方案。第一种采用双NPN三极管实现3.3V转5V反相电平转换;第二种使用单NPN三极管完成5V转3.3V同相转换;第三种利用单PNP三极管实现3.3V转5V同相转换。各方案均通过三极管的开关特性配合电阻网络实现电压域适配,具有结构简单、成本低的优点,适用于不同逻辑电平设备(如MCU与外设)间的信号兼容传输。文中详细分析了各电路的工作原理、元件作用和特性,并通过Multisim仿真验证了其功能有效性。

XU157303764的博客 1855

第3章 栈和队列

第3章栈和队列栈1.知识点提要1.栈的定义及基本运算2.栈的混洗3.栈的顺序存储结构1.顺序栈的两种存储分配1.静态存储分配2.动态存储分配2.两种进栈和出栈处理3.两个顺序栈共用一个存储空间4.栈的链式存储结构5.理解栈的存储结构的要点 栈 1.知识点提要 1.栈的定义及基本运算 2.栈的混洗 问:如果列车按照1,2,3,,,n进站,那么有多少种情况出栈?不可能的情况有多少种? 答:根据ca...

kingKINGabduxhbs的博客 1477

“/usr/lib/wsl/wsl-setup“ failed, exiting

WSL2安装Ubuntu时出现&quot;wsl-setup failed&quot;错误的解决方法 摘要:当Windows用户名包含中文字符时,安装WSL2+Ubuntu会出现&quot;wsl-setup failed&quot;错误。本文提供两种解决方案:1)修改中文用户名(风险较大);2)通过命令手动配置。推荐第二种方法:先使用&quot;wsl -l -v&quot;查看Ubuntu名称,再通过&quot;wsl -d Ubuntu20.04 -e /bin/bash&quot;命令启动WSL2系

猿小白的博客 994

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

广度优先搜索

注:最近有些事所以请大家原谅那么废话讲完了┏ (゜ω゜)=☞。

Mark1277的博客 7191

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

广度优先搜索和深度优先搜索

假设从a结点开始访问,a先入队。例题:在一个n*m的矩阵上,分布着如下数字,0代表通路,1代表墙,无法通行,2代表起点,3代表终点,4代表陷阱,6代表炸弹,现在要求从起点到终点的最短路径,0可以通行,1无法通行,陷阱则需要花费3个单位时间,6可以把上下左右的四个坐标炸为通路,请给出从起点到终点的最短距离。在广度遍历的过程中,我们可以得到一棵遍历树,称为广度优先生成树,需要注意的是,一给定图的邻接矩阵存储表示是唯一的,故其广度优先生成树也是唯一的,但由于邻接表存储表示不唯一,故其广度优先生成树也是不唯一的。

liulanba的博客 6507

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

算法数据结构——图的遍历之广度优先搜索算法(Breadth First Search)

广度优先搜索算法(Breadth First Search):简称为 BFS,又译作宽度优先搜索 / 横向优先搜索。是一种用于遍历或搜索树或图的算法。该算法从根节点开始,沿着树的宽度遍历树或图的节点。如果所有节点均被访问,则算法中止。广度优先遍历类似于树的层次遍历过程。呈现出一层一层向外扩张的特点。先看到的节点先访问,后看到的节点后访问。遍历到的节点顺序符合「先进先出」的特点,所以广度优先搜索可以通过「队列」来实现。

白话机器学习 9399

数据结构与算法——BFS(广度优先搜索)

广度优先搜索(Breadth-First Search,简称BFS)是一种遍历或搜索树和图的算法,也称为宽度优先搜索,BFS算法从图的某个节点开始,依次对其所有相邻节点进行探索和遍历,然后再对这些相邻节点的相邻节点进行探索,直到遍历完所有的节点。

闻道有先后,术业有专攻 1万+

广度优先搜索(BFS)算法详解

int x;// 当前点的x坐标int y;// 当前点的y坐标int step;// 从起点到当前点的步数}P;N和M定义了数组的最大尺寸P结构体表示迷宫中的一个点,包含坐标和到达该点的步数。

不语的博客 4424

数据结构与算法(四) 广度优先搜索

本篇文章继续来学习广度优先搜索算法(Broad-First-Search,BFS)

半虹小站 3303

【Python搜索算法】广度优先搜索(BFS)算法原理详解与应用,示例+代码

广度优先搜索(Breadth-First Search,BFS)是一种图遍历算法,用于系统地遍历或搜索图(或树)中的所有节点。BFS的核心思想是从起始节点开始,首先访问其所有相邻节点,然后逐层向外扩展,逐一访问相邻节点的相邻节点,以此类推。这意味着BFS会优先探索距离起始节点最近的节点,然后再逐渐扩展到距离更远的节点。BFS通常用于查找最短路径、解决迷宫问题、检测图是否连通以及广泛的图问题。BFS算法的步骤如下:初始化:选择一个起始节点,将其标记为已访问,并将其放入队列中(作为起始节点)。

qq_35831906的博客 1万+

广度优先搜索算法

搜索

实践求真知 4263

啊啊

深度优先搜索和广度优先搜索,都是图形搜索算法,它两相似,又却不同,在应用上也被用到不同的地方。这里拿一起讨论,方便比较。 一、深度优先搜索 深度优先搜索属于图算法的一种,是一个针对图和树的遍历算法,英文缩写为DFS即Depth First Search。深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路...

qq_44228642的博客 343

【图计算算法‌】广度优先搜索(BFS)算法

广度优先搜索(BFS)算法是一种在图或树数据结构中广泛应用的遍历算法。它按照从起始节点开始,逐层向外扩展的顺序访问节点,直到找到目标节点或遍历完所有可达的节点

大雨淅淅的博客 4674
上一篇: 【SQL】(重难点)嵌套查询
下一篇: 【算法】算法设计基础
bubblecheese
博客等级 码龄5年 153粉丝 20原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值