算法第十二期——BFS-双向广搜

news2024/11/25 22:55:12

双向广搜

  • 应用场景有确定的起点s和终点t;把从起点到终点的单向搜索,变换为分别从起点出发和从终点出发的“相遇”问题
  • 操作:从起点s(正向搜索)和终点t(逆向搜索)同时开始搜索,当两个搜索产生相同的一个子状态v时就结束,v是相遇点。得到的s-v-t是一条最佳路径。
  • 队列:一般用两个队列分别处理正向BFS和逆向BFS

双向广搜的复杂度

当下一层扩展的状态很多时,双向广搜能大大优化,减少大量搜索。
 图(1)单个BFS搜索到第四层需要搜索1+2+4+8+16=32次,二图(2)双向BFS只需要1+2+4+2+1=10次,显然效率更高。

注意: 双向广搜对二叉树有很大的优化,但对网格图并没有很好的效果。

例题:跳蚱蜢

 跳蚱蜢2017年第八届省赛,lanqiao0J题号642

【题目描述】

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

如下图所示: 有 9 只盘子,排成 1 个圆圈。 其中 8 只盘子内装着 8 只蚱蜢,有一个是空盘。 我们把这些蚱蜢顺时针编号为 1 ~ 8。

每只蚱蜢都可以跳到相邻的空盘中, 也可以再用点力,越过一个相邻的蚱蜢跳到空盘中。

请你计算一下,如果要使得蚱蜢们的队形改为按照逆时针排列, 并且保持空盘的位置不变(也就是 1−8 换位,2−7换位,...),至少要经过多少次跳跃?

【思路】 

队列q1:正向搜索

队列q2:逆向搜索
由于起点和终点的串不同,正向BFS和逆向BFS扩展的下一层数量也不同,也就是进入2个队列的串的数量不同,先处理较小的队列,可以加快搜索速度。

 建模

  • 直接让蚱蜢跳到空盘有点麻烦,因为有很多在跳蚱蜢。
  • 每一次跳跃有一只蚱蜢跳到空盘,如果我们反过来看,让空盘跳,跳到蚱蜢的位置,简单多了,每个队列只有一个空盘在跳。

化圆为线

  • 题目是一个圆圈,不好处理,用一个建模技巧“化圆为线”,把圆形转换为线形。
  • 把空盘看成0,有9个数字{0,1,2,3,4,5,6,7,8},一个圆圈上的9个数字,拉直成了一条线上的9个数字,这条线的首尾两个数字0和8处理成相连的。
  • 八数码问题:有9个数字{0,1,2,3,4,5,6,7,8},共有9!=362880种排列(10w种),不算多。 

最短路径

  •  用BFS扩展每一层,每一层就是蚱蜢(建模成‘’空盘‘’)跳了一次。
  • 初始状态(队列1):“012345678”,目标状态(队列2):“087654321”。
  • 从初始状态“012345678”跳一次,有4种情况:0跳到1(向右跳一个),2(向右跳两个),7(向左跳一个),8(向左跳两个)这几个点,即“1023456783"、“210345678”、“812345670”、“712345608",等价于交换了空盘编号0和空盘跳到的蚂蚱编号。同样的,从目标状态“087654321”跳一次也是4这种情况。
  • 然后从这4种状态继续跳到下一种状态,一直跳到目标状态为止,队列1的状态第一次出现在队列2中就是出现了最短路径,记录步数:正向搜索步数+当前这一步+逆向搜索步数。

【代码】 

from queue import *
cnt = 0
meet = False
def extend(q,m1,m2):
    global cnt
    global meet
    s = q.get() # 弹出队首状态
    for i in range (len(s) ):   # 找出该状态下0的位置
        if s[i]=='0': break
    for j in range(4): # 四种跳的情况:左1,左2,右1,右2
        cnt += 1            #统计计算次数
        news = list(s)      # 把字符串转成list,后面方便处理
        # 化圆为方
        if j==0: news[(i-2+9)%9] ,news[i] = news[i], news[(i-2+9)%9] # 往左跳1个,把跳到的数与0交换
        if j==1: news[(i-1+9)%9], news[i] = news[i], news[(i-1+9)%9] # 往左跳2个
        if j==2: news[(i+1+9)%9], news[i] = news[i], news[(i+1+9)%9] # 往右跳1个
        if j==3: news[(i+2+9)%9], news[i] = news[i], news[(i+2+9)%9] # 往右跳2个
        a = "".join(news)   # 处理完再转回字符串重新转成字符串
        if a in m2:         # 结束条件:第一次相遇(队列1的状态在队列2里出现过),就是最短路径
            print(m1[s] + 1 + m2[a])    # 正向搜索的步数+当前这一步+逆向搜索的步数
            # print(cnt)    # 打印计算次数:54560
            meet = True
            return
        if a not in m1:     # 若该状态不在队列1
            q. put(a)       # 加入队列
            m1[a] = m1[s]+1        # 向字典中添加状态和当前步数
    meet = False
q1 = Queue()  # 正向搜索
q2 = Queue()  # 逆向搜索
q1.put("012345678")
q2.put("087654321")
mp1={'012345678':0}   # 定义字典(用于判重):状态,当前步数
mp2={'087654321':0}
while not q1.empty() and not q2.empty(): # 两个队列都不为空
    if q1.qsize() <= q2.qsize() : extend(q1, mp1, mp2) # 若队列1较小,先处理队列1
    else:                         extend(q2, mp2, mp1) # 若队列2较小,先处理队列2
    if meet==True: break    # 相遇就结束

 计算量:

  • 用cnt统计运行了多少次:54568次。
  • 前面用普通BFS计算:1451452次
  • 双向广搜的计算量只有4%

为什么能优化这么多?
在普通BFS中,如果不判重,到第20层扩展了4^{20}种状态。在双向广搜中,假设在第10层相遇,正向搜索和逆向搜索在第10层扩展的状态数量都是4^{10},从4^{20}4^{10},得到了极大优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/167520.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring入门-Spring事务管理

文章目录1&#xff0c;Spring事务管理1.1 Spring事务简介1.1.1 相关概念介绍1.1.2 转账案例-需求分析1.1.3 转账案例-环境搭建步骤1:准备数据库表步骤2:创建项目导入jar包步骤3:根据表创建模型类步骤4:创建Dao接口步骤5:创建Service接口和实现类步骤6:添加jdbc.properties文件步…

数据治理与档案信息资源体系建设

如果要评选大数据或者数字化转型领域中哪个词最让人费解、最讲不清楚&#xff0c;“数据治理&#xff08;Data Governance&#xff09;”绝对是候选之一。说实话&#xff0c;笔者到现在也没有完全整明白&#xff0c;因为数据治理包含的范围太广了&#xff0c;可以说是包罗万象&…

高潜人才的自我要求

前言&#xff0c;上次写了个《潜力出众的你有这样的特质吗&#xff1f;》&#xff0c;地址如下&#xff1a;点我查看&#xff0c;这次在写个高潜人才的自我要求。本次以6个纬度来进行分析&#xff1b;3是基本要求&#xff0c;4是追求卓越&#xff0c;看你目前做到了哪个级别&am…

跨平台API对接(Python)的使用

Jenkins 是一个开源的、提供友好操作界面的持续集成(CI)工具&#xff0c;起源于 Hudson&#xff08;Hudson 是商用的&#xff09;&#xff0c;主要用于持续、自动的构建/测试软件项目、监控外部任务的运行。后端可以利用 Jenkins 对任务进行调度运行&#xff1a;后端可利用 HTT…

【进阶】Spring更简单的读取和存储对象

努力经营当下&#xff0c;直至未来明朗&#xff01; 文章目录一、存储Bean对象一&#xff09;前置工作&#xff1a;配置扫描路径&#xff08;重要&#xff09;二&#xff09;添加注解存储Bean对象3. 五大类注解&#xff1a;4. 方法注解&#xff1a;6. 相关问题7. 补充【结论、查…

ROS2机器人编程简述humble-第二章-DEVELOPING THE FIRST NODE .2

0.1ROS2机器人编程简述新书推荐-A Concise Introduction to Robot Programming with ROS21.1ROS2机器人编程简述humble-第一章-Introduction2.1ROS2机器人编程简述humble-第二章-First Steps with ROS2 .12.2主要内容是全手工创建一个最简单的自定义节点&#xff0c;其实没啥具…

IB学生必看的时间表(二)

上期谈到在IB预科课程的第一个学年下学期&#xff0c;便要开始作报读大学的准备&#xff0c;到底为什么&#xff1f; 暑假不容松懈 现在来到放暑假了。虽说不用上课&#xff0c;学生没有了学习压力&#xff0c;但就以下三方面来看&#xff0c;学生还是要继续投放心力。 首先&am…

Unity 之 Addressable可寻址系统 -- 代码加载介绍 -- 进阶(一)

Unity 之 可寻址系统 -- 代码加载介绍 -- 进阶&#xff08;一&#xff09;一&#xff0c;可寻址系统代码加载1.1 回调形式1.2 异步等待1.3 面板赋值1.4 同步加载二&#xff0c;可寻址系统分标签加载2.1 场景搭建2.2 代码示例2.3 效果展示三&#xff0c;代码加载可寻址的解释概述…

Cadence OrCAD: 跨页符和电源符号命名优先级的一个小问题

Cadence OrCAD: 跨页符和电源符号命名优先级的一个小问题 遇到的问题 最近项目中&#xff0c;有个电源需要做负载端的反馈&#xff0c;类似下图的signal1和signal1N&#xff0c;反馈使用类似伪差分线&#xff0c;把电压信号和负载端的GND都连到DC-DC控制器。DC-DC对应的反馈引…

字节跳动青训营--前端day1

文章目录前言一、 前端1 前端的技术栈2. 前端的边界3. 前端的关注点二、 HTML1. HTML常用标签及语义化2. HTML 语法3. 谁在使用我们写的HTML前言 仅以此文章记录学习历程 一、 前端 解决GUI人机交互问题 1 前端的技术栈 2. 前端的边界 nodejs–服务器端应用 electron… --客…

【数据结构】6.1 图的基本概念和术语

文章目录前言6.1 图的定义和术语前言 图是一种比线性表和树更为复杂的数据结构。 在线性结构中&#xff0c;结点之间的关系属于一个对一个&#xff1b;数据元素之间有着线性关系&#xff0c;每个数据元素只有一个直接前趋和一个直接后继&#xff0c; 在树形结构中&#xff0c;…

算法设计与分析课程

算法的由来 算法的定义 算法的定义&#xff1a;给定计算问题&#xff0c;算法是一系列良定义的计算步骤&#xff0c;逐一执行计算步骤可得到预期的输出。 良定义&#xff1a;定义明确无歧义 计算步骤&#xff1a;计算机可以实现的指令 有了良定义的计算步骤&#xff0c;计算机就…

Java基础篇01-运算符的使用

01| Java中的数据类型 ) 1. 数值型&#xff1a; 序号类型空间占用说明最小值最大值默认值优缺点对比举例1byte8位有符号整数-128(-2^7)127 (2^7-1)0byte 类型用在大型数组中节约空间&#xff0c;主要代替整数&#xff0c;因为 byte 变量占用的空间只有 int 类型的四分之一by…

6、Denoising Diffusion Probabilistic Models(扩散模型)

简介 主页&#xff1a;https://hojonathanho.github.io/diffusion/ 扩散模型 &#xff08;diffusion models&#xff09;是深度生成模型中新的SOTA。 扩散模型在图片生成任务中超越了原SOTA&#xff1a;GAN&#xff0c;并且在诸多应用领域都有出色的表现&#xff0c;如计算机…

【docker概念和实践 1】 基本概念和组成原理

一、说明 初学Docker就一个字&#xff1a;乱&#xff01;这是因为Docker是一个庞大体系&#xff0c;初学时不了解全貌&#xff0c;处于“盲人摸象”状态&#xff0c;因不能通晓要领&#xff0c;学了一点&#xff0c;过后就忘了。而了解Docker全貌并非易事&#xff0c;官方文档也…

前端学习记录-Javascript

pink JS基础语法JavaScript核心教程阮一峰JS基础 JS基础语法 初识JS JS三种书写位置&#xff1a;行内、内嵌、引入式。单行注释 ctrl/ 多行注释 shift alt a输入输出语句 声明变量 var age;变量命名规范&#xff1a;字母、数字、下划线、美元符号组成&#xff0c;区分大小写…

质量体系搭建

测试团队的发展历程 初期阶段 特点&#xff1a;提供“保姆式”服务&#xff0c;以发现BUG为主要任务。 工作主要&#xff1a;以功能测试、兼容行测试为主的手工测试&#xff0c;每天进行大量的、重复性的工作&#xff0c;即便如此依然会有遗漏。刚起步的测试团队基本处于这个阶…

LeetCode分类刷题----哈希表篇

哈希表哈希表1.有效的字母异位词242.有效的字母异位词383.赎金信49.字母异位词分组438.找到字符串中所有字母异位词2.两个数组的交集349.两个数组的交集350.两个数组的交集||3.快乐数202202.快乐数4.两数之和1.两数之和5.四数相加454.四数相加||6.三数之和15.三数之和7.四数之和…

ARM 实时时钟 RTC

一、何为实时时钟 (1) real time clock&#xff0c;真实时间&#xff0c;就是所谓的xx年x月x日x时x分x秒星期x. (2) RTC是 SoC 中一个内部外设&#xff0c;RTC 有自己独立的晶振提供 RTC 时钟源&#xff08;32.768KHz&#xff09;&#xff0c;内部有一些寄存器用来记录时间&am…

微信小程序登陆,后端接口实现 - springboot

登录流程 1、通过调用wx.login获取登录凭证&#xff08;code&#xff09; uni-app通过调用uni.login 2、前端将code提交给服务器&#xff0c;springboot访问 auth.code2Session&#xff0c;使用 code 换取 openid、unionid、session_key 等信息。 3、完成登录操作&#xff0…