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

news2024/11/24 10:16:44

双向广搜

  • 应用场景有确定的起点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/168932.html

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

相关文章

编程太难不适合女生学?来看 N 多小姐姐的回应!

某女程序员&#xff1a;我要去互联网公司做程序员&#xff1f;网友&#xff1a;你疯了&#xff1f;程序员很累的... 女生不适合做程序员&#xff0c;还是去做产品经理吧。画外音&#xff1a;我去&#xff0c;产品经理不累吗&#xff1f;并不是女生不适合写代码&#xff0c;也不…

python cairosvg 库专题博客,10分钟掌握 cairosvg

cairosvg 库用于将 SVG 图像转换为其他图片格式。它使用 Cairo 库来绘制 SVG 图像&#xff0c;并支持将 SVG 图像转换为 PNG、PDF、PS、SVG 和 GIF 格式。 python cairosvgPython cairosvg 上手案例cairosvg 直接将 svg 图像转换为二进制数据cairosvg 库函数清单总结Python cai…

趣味三角——第1章——角

平面角是平面内相交但不在一条直线上的两条直线之间的倾角(A plane angle is the inclination to one another of two lines in a plane which meet one another and do not lie in a straight line.)。 ——Euclid(欧几里得), 元素(The Elements)&#xff0c;定义8。 几何实体…

【C++】Hash开散列,unordered_set(map) 的封装以及迭代器的实现

上一篇博客我们使用闭散列的方式实现了 Hash&#xff0c;其实在STL库unordered_set、unordered_map中底层是开散列的方式实现的Hash&#xff0c;所以&#xff0c;本篇博客就再使用开散列的方式实现Hash&#xff0c;并将unordered_set、unordered_map进行封装。 目录 一、开散…

C 数据结构1 —— 线性表-顺序表\单链表\双链表

文章目录1. 线性表1.1 定义1.2 特点2. 顺序表(顺序存储结构)2.1 定义(存储结构代码描述)2.2 插入元素2.2.1 图形演示2.2.2 代码表示2.3 删除元素2.3.1 图形演示2.3.2 代码表示2.4 完整代码2.5 动态分配数组3. 单链表(链式存储结构)3.1 定义(存储结构代码描述)3.2 单链表的读取3…

COCO_04 展示COCO格式数据集 目标框与分割mask

文章目录1 前言2 绘制GT2.1 绘制目标框与类别2.2 绘制分割mask3 AppendixA. mask polygon格式转化为图片格式参考1 前言 上篇文章介绍了如何制作COCO个数数据集的Dataset与Dataloader&#xff0c;并绘制了dataloader->batch的返回的信息&#xff0c;https://blog.csdn.net/…

【打卡】医学搜索Query相关性判断学习赛

入坑传送门 赛事介绍 文本匹配拥有广泛的应用场景&#xff0c;可以用于去除重复问题和文本相似度中。在本次学习中我们将学习&#xff1a; 如何计算文本之间的统计距离如何训练词向量 & 无监督句子编码BERT模型搭建和训练 上述步骤都是一个NLP算法工程师必备的基础&…

【GD32F427开发板试用】02-ADC规则组连续采样

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;Stark_GS ADC 简介及特点 器件中集成了一个 12 位 2.6 MSPS 多通道 ADC。 一共有19个多路复用通道&#xff1a;16个外部通道&#xff0c;1个…

office365删除错误发送的邮件

微软喜欢变&#xff0c;office365删个邮件真是不容易。 --管理员登录 Connect-IPPSSession -UserPrincipalName adminmydomain.onmicrosoft.com --创建一个 "deleteemail"的搜索项目&#xff0c;项目名可以任意起&#xff0c;这个名称后面在office365安全合规门户里…

libcurl简介及其编程应用

本文为学习笔记&#xff0c;整合课程内容以及下列文章&#xff1a; 其中&#xff0c;libcurl函数库常用字段解读部分&#xff1a; 参考博文&#xff1a;原文地址 作者&#xff1a;冬冬他哥哥 目录 libcurl简介 libcurl的使用 学会开源包使用的一般步骤 包的解读 重点是看…

Spark 核心编程

文章目录Spark 核心编程一、RDD1、分布式计算模拟(1) 搭建基础的架子(2) 客户端向服务器发送计算任务Spark 核心编程 Spark 计算框架为了能够进行高并发和高吞吐的数据处理&#xff0c;封装了三大数据结构&#xff0c;用于处理不同的应用场景。三大数据结构分别是&#xff1a;…

【数据结构与算法理论知识点】1.1基本概念

1.1基本概念 为什么要学习数据结构与算法&#xff1f; AlgorithmsData StructuresPrograms---- Niklaus Wirth ( Pascal程序设计语言之父、结构化程序设计首创者、图灵奖获得者) 计算机程序&#xff1a;使用计算机求解问题算法是求解问题的步骤的描述&#xff1a;从蛮力到策…

套接字编程(二)UDP服务端与客户端的通信模拟实现

目录 一、前言 二、UDP客户端流程信息 1、创建套接字 2、为套接字绑定地址信息&#xff08;不推荐&#xff09; 3、发送数据&#xff08;将数据放入发送缓冲区中&#xff09; 4、接收数据&#xff08;从socket结构体接收缓冲区中取出数据&#xff09; 5、关闭套接字 三…

机器学习基本概念及问题梳理

前言&#xff1a;整理西瓜书第一、二章中的基本概念 待办&#xff1a;第二章评估方法、性能度量及后续内容未整理 下图梳理机器学习中部分概念 模型评估与选择相关知识点&#xff1a; 错误率&#xff08;error rate, E&#xff09;&#xff1a;如果在m个样本中有a个样本分类…

WordPress安全指南:19个步骤让您的WordPress安全防线坚如磐石

谈到WordPress安全性&#xff0c;您可以采取很多措施来锁定您的网站&#xff0c;以防止黑客和漏洞影响您的电子商务网站或博客。您最不想发生的事情是一天早上醒来发现您的网站一团糟。因此&#xff0c;今天我们将分享许多技巧、策略和技术&#xff0c;您可以使用这些技巧、策略…

WEBSHELL管理工具流量特征——基础篇

前言 前一阵子帮别人做取证题目&#xff0c;有很多关于WEBSHELL的流量要分析&#xff0c;想起来还有没好好分析过于是准备写篇文章总结一下帮助大家能够快速的辨别WEBSHELL流量&#xff0c;下面我们展开文章来讲。 中国菜刀 这个应该是大家最熟悉的WEBSHELL管理工具&#xf…

NeuRay学习笔记

Neural Rays for Occlusion-aware Image-based Rendering 主页&#xff1a;https://liuyuan-pal.github.io/NeuRay/ 论文&#xff1a;https://arxiv.org/abs/2107.13421 Code&#xff1a;https://github.com/liuyuan-pal/NeuRay 效果&#xff1a; desktop摘要 We present a ne…

一文读懂 UniProt 数据库(2023 最新版)

一、UniProt 数据库介绍 Uniprot &#xff08;Universal Protein &#xff09;是包含蛋白质序列&#xff0c;功能信息&#xff0c;研究论文索引的蛋白质数据库&#xff0c;整合了包括EBI&#xff08; European Bioinformatics Institute&#xff09;&#xff0c;SIB&#xff0…

【面试题】前端最新面试题-浏览器 dom、bom篇

原文见&#xff1a;语雀&#xff08;https://www.yuque.com/deepstates/interview/fsitlt&#xff09; ● BOM ● window对象 ○ frames ■ iframe ■ 跨窗口通信 ■ 同源策略/跨域 ○ navigator ● DOM ○ DOM结构 ○ DOM操作 ○ DOM事件 ■ 表单事件 ● 浏览器渲染 ○ 进程、…

Vue组件化编程的组件通信

对于组件化编程&#xff0c;组件之间的通信技术无疑是非常重要的内容&#xff0c;需要将细节牢牢把握。 组件通信&#xff0c;就是子组件放置在父组件内之后&#xff0c;父组件如何向子组件传递参数以及子组件如何与外部组件进行互动。 这部分的知识很重要&#xff0c;需要展开…