C++ 算法学习——1.3 双向深度优先搜索
双向深度优先搜索(Bidirectional Depth-First Search)是一种图搜索算法,旨在通过从起始节点和目标节点同时开始,沿着深度优先搜索的路径向前探索,以减少搜索空间并提高搜索效率。
1. 基本原理
- 双向深度优先搜索同时从起始节点和目标节点开始搜索,通过交替地在两个方向上进行深度优先搜索,直到两个搜索路径相遇。
2. 算法步骤
- 初始化两个空的栈,一个用于从起始节点开始的搜索,另一个用于从目标节点开始的搜索。
- 将起始节点和目标节点分别推入两个栈。
- 从两个栈中分别出栈一个节点,进行如下操作:
- 标记节点为已访问。
- 检查当前节点是否在两个搜索方向上相遇,如果相遇则搜索结束。
- 否则,对当前节点的未访问邻居节点进行处理:
- 对于起始节点搜索方向,将未访问的邻居节点推入起始栈。
- 对于目标节点搜索方向,将未访问的邻居节点推入目标栈。
- 重复步骤3,直到两个栈中的节点相遇或者两个栈都为空。
3. 优缺点
- 优点:
- 相较于单向深度优先搜索,双向深度优先搜索在搜索空间较大时能够更快地找到目标节点。
- 缺点:
- 需要额外的内存空间来维护两个搜索方向的栈。
- 在特定情况下可能会比单向搜索更慢,例如在目标节点附近的情况。
代码示例(邻接表表示的图):
#include <iostream>
#include <vector>
#include <stack>
#include <unordered_set>using namespace std;// 无权图的邻接表表示
vector<vector<int>> graph;// 双向深度优先搜索函数
bool bidirectionalDFS(int start, int target) {stack<int> startStack, targetStack;unordered_set<int> startVisited, targetVisited;startStack.push(start);targetStack.push(target);while (!startStack.empty() && !targetStack.empty()) {int currentStart = startStack.top();int currentTarget = targetStack.top();startStack.pop();targetStack.pop();startVisited.insert(currentStart);targetVisited.insert(currentTarget);// 检查是否相遇if (startVisited.count(currentTarget) || targetVisited.count(currentStart)) {cout << "Nodes met at: " << (startVisited.count(currentTarget) ? currentTarget : currentStart) << endl;return true;}//对于std::unordered_set和std::unordered_map,count函数会返回1(存在)或0(不存在)。// 处理邻居节点for (int neighbor : graph[currentStart]) {if (!startVisited.count(neighbor)) {startStack.push(neighbor);}}for (int neighbor : graph[currentTarget]) {if (!targetVisited.count(neighbor)) {targetStack.push(neighbor);}}}cout << "Nodes did not meet." << endl;return false;
}
代码示例(矩阵模样,起点坐标begina,beginb,目标点坐标enda,endb):
#include <iostream>
#include <stack>
#include <unordered_set>
using namespace std;
int n,m;
char** board;
void showcurboard()
{for(int i=0;i<n;i++){for(int j=0;j<m;j++)cout<<board[i][j];cout<<endl;}
}
struct PairHash {template <class T1, class T2>std::size_t operator () (const std::pair<T1, T2> &pair) const {auto hash1 = std::hash<T1>{}(pair.first);auto hash2 = std::hash<T2>{}(pair.second);return hash1 ^ hash2;}
};
// 双向深度优先搜索函数
bool bidirectionalDFS(int begina, int beginb, int enda, int endb) {stack<pair<int, int>> startStack, targetStack;unordered_set<pair<int, int>,PairHash> startVisited;unordered_set<pair<int, int>,PairHash> targetVisited;startStack.push({begina, beginb});targetStack.push({enda, endb});while (!startStack.empty() && !targetStack.empty()) {auto currentStart = startStack.top();auto currentTarget = targetStack.top();startStack.pop();targetStack.pop();startVisited.insert(currentStart);targetVisited.insert(currentTarget);// 检查是否相遇if (startVisited.count(currentTarget) || targetVisited.count(currentStart)) {return true;}// 处理邻居节点int dirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};for (auto dir : dirs) {int nextStartA = currentStart.first + dir[0];int nextStartB = currentStart.second + dir[1];if (nextStartA >= 0 && nextStartA < n && nextStartB >= 0 && nextStartB < m &&!startVisited.count({nextStartA, nextStartB})) {startStack.push({nextStartA, nextStartB});}int nextTargetA = currentTarget.first + dir[0];int nextTargetB = currentTarget.second + dir[1];if (nextTargetA >= 0 && nextTargetA < n && nextTargetB >= 0 && nextTargetB < m &&!targetVisited.count({nextTargetA, nextTargetB})) {targetStack.push({nextTargetA, nextTargetB});}}}return false;
}int main()
{cin>>n>>m;board=new char*[n];for(int i=0;i<n;i++){board[i]=new char[m];for(int j=0;j<m;j++) cin>>board[i][j];}showcurboard();return 0;
}
P1. b3625迷宫寻路

#include <iostream>
#include <stack>
#include <unordered_set>
using namespace std;
int n,m;
char** board;
void showcurboard()
{for(int i=0;i<n;i++){for(int j=0;j<m;j++)cout<<board[i][j];cout<<endl;}
}
struct PairHash {template <class T1, class T2>std::size_t operator () (const std::pair<T1, T2> &pair) const {auto hash1 = std::hash<T1>{}(pair.first);auto hash2 = std::hash<T2>{}(pair.second);return hash1 ^ hash2;}
};
// 双向深度优先搜索函数
bool bidirectionalDFS(int begina, int beginb, int enda, int endb) {stack<pair<int, int>> startStack, targetStack;unordered_set<pair<int, int>,PairHash> startVisited;unordered_set<pair<int, int>,PairHash> targetVisited;startStack.push({begina, beginb});targetStack.push({enda, endb});while (!startStack.empty() && !targetStack.empty()) {auto currentStart = startStack.top();auto currentTarget = targetStack.top();startStack.pop();targetStack.pop();startVisited.insert(currentStart);targetVisited.insert(currentTarget);// 检查是否相遇if (startVisited.count(currentTarget) || targetVisited.count(currentStart)) {return true;}// 处理邻居节点int dirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};for (auto dir : dirs) {int nextStartA = currentStart.first + dir[0];int nextStartB = currentStart.second + dir[1];if (nextStartA >= 0 && nextStartA < n && nextStartB >= 0 && nextStartB < m &&!startVisited.count({nextStartA, nextStartB})&&board[nextStartA][nextStartB]=='.') {startStack.push({nextStartA, nextStartB});}int nextTargetA = currentTarget.first + dir[0];int nextTargetB = currentTarget.second + dir[1];if (nextTargetA >= 0 && nextTargetA < n && nextTargetB >= 0 && nextTargetB < m &&!targetVisited.count({nextTargetA, nextTargetB})&&board[nextTargetA][nextTargetB]=='.') {targetStack.push({nextTargetA, nextTargetB});}}}return false;
}int main()
{cin>>n>>m;board=new char*[n];for(int i=0;i<n;i++){board[i]=new char[m];for(int j=0;j<m;j++) cin>>board[i][j];}//showcurboard();bool ans=bidirectionalDFS(0,0,n-1,m-1);if(ans) cout<<"Yes";else cout<<"No";return 0;
}
相关文章:
C++ 算法学习——1.3 双向深度优先搜索
双向深度优先搜索(Bidirectional Depth-First Search)是一种图搜索算法,旨在通过从起始节点和目标节点同时开始,沿着深度优先搜索的路径向前探索,以减少搜索空间并提高搜索效率。 1. 基本原理 双向深度优先搜索同时从…...
Artistic Oil Paint 艺术油画着色器插件
只需轻轻一点,即可将您的视频游戏转化为艺术品!(也许更多…)。 ✓ 整个商店中最可配置的选项。 ✓ 六种先进算法。 ✓ 细节增强算法。 ✓ 完整的源代码(脚本和着色器)。 ✓ 包含在“艺术包”中。 …...
记一次left join联表查询的索引失效场景
结论:关联表的列的字符集不一致导致的 场景:user_t(用户表)、org_t(机构表),user_t的org_id和org_t的id是一对一关系 1.explain发现org_t表未走索引,但是org_t的id字段默认存在主键…...
从零到一:前端开发者学习 Cocos Creator 的全攻略
大家好,我是小蜗牛。 作为一名前端开发者,掌握 Cocos Creator 是一个非常有趣且充满潜力的技能。Cocos Creator 是一款免费开源的游戏开发引擎,它的工作流和前端开发非常相似,因此前端开发者可以较快上手,并通过开发小…...
JavaWeb 19 AJAX
目录 一、什么是AJAX 同步交互和异步交互 同步交互 异步交互 Ajax工作原理 Ajax实现方式 原生JavaScript方式进行ajax(了解): "我就是希望你好,就像很多人希望我好一样,特别简单,特别真挚。也不为了什么,就是希望…...
element plus中menu菜单技巧
我在使用element plus的menu(侧边栏)组件的过程中遇到了一些问题,就是menu编写样式和路由跳转,下面给大家分享以下,我是怎么解决的。 1.页面效果 我要实现的网站布局是这样的: 侧边栏折叠以后的效果&#…...
数据结构-贪心算法笔记
前言:贪心无套路,狠狠刷就完事 分发饼干 455. 分发饼干 - 力扣(LeetCode) class Solution {/*** 找出最多有多少个孩子可以得到糖果。** param g 一个数组,表示每个孩子对糖果大小的满意度。* param s 一个数组&…...
基于SpringBoot的在线汽车票预订平台
1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管理汽车票网上预订系统的相关信息成为必然。开…...
ubuntu 安装nginx
sudo apt-get update sudo apt-get install nginx sudo nginx -vsudo systemctl status nginx sudo systemctl start nginx sudo systemctl stop nginx sudo systemctl restart nginx#浏览器输入:http://192.168.31.181/#查看文件结构 cd /etc/nginx sudo cp nginx.…...
fanuc远程PNS启动
参考 PNS & RSR区别 前者是8bit255 个程序 后者是bitN对应8个程序...
使用 Spring 框架构建 MVC 应用程序:初学者教程
Spring Framework 是一个功能强大、功能丰富且设计精良的 Java 平台框架。它提供了一系列编程和配置模型,旨在简化和精简 Java 中健壮且可测试的应用程序的开发过程。 人们常说 Java 太复杂了,构建简单的应用程序需要很长时间。尽管如此,Jav…...
集成Spring Security详解
集成Spring Security详解 一、Spring Security简介 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架,它专注于为Java应用程序提供全面的安全解决方案。作为Spring项目的一部分,Spring Security继承了Spring框架的灵活性和可扩展性…...
Kettle9.4支持Clickhouse数据源插件开发以及性能测试
前言 最近业务这边有个指标需要用到大数据这边的列式数据库进行处理,由于kettle不支持clickhouse数据源驱动,这里查了一下网上的相关资料,发现了一些别人开发好的驱动包,下载下来后使用效果不尽人意。总结下来有以下几个问题&…...
微信支付V3 yansongda/pay 踩坑记录
Pay - 让支付开发更简单 | Pay 使用laravel 8框架 2.1 报错 Parse [mch_public_cert_path] Serial Number Error 是mch_secret_cert,mch_public_cert_path配置错误 2.2 报错 Get Wechat Public Cert Error 是mch_secret_key配置错误 #正确 Pay::config(config(w…...
AndroidStudio实验报告——实验一、二
目录 实验一: AS安装与安卓环境搭建 一、实验目标 二、实验内容 (一)Android Studio安装 (二)JDK安装与配置 (三)Android SDK安装与配置 三、实验结果:(实…...
Nginx超简洁知识:负载均衡-反向代理,动静分离,配置文件
首先介绍一下为什么需要nginx? 在低并发场景下(也就是用户量特别少的情况下),我们只需要部署一台服务器就能满足用户数量少的需求。 但是如果用户量逐渐增多,只有一台服务器是不够的。于是我们需要部署多台服务器。 …...
云手机:社交平台运营的热门工具
随着互联网的飞速发展,社交平台已经成为企业推广和营销的核心渠道。传统的运营方式已经无法满足高效运营的需求,而云手机作为新兴工具,逐渐成为社交平台运营的前沿趋势。本文将深入分析云手机如何优化社交平台的运营流程,助力企业…...
iptables限速规则
环境: iptables服务器:172.16.12.33 client:192.168.1.2 1、在防火墙上配置客户端的下载速度是1M/s (1个包是1.3KB) #限速客户端每秒的下载速度是1024KB,超出限制的流量就丢弃 [rootiptables-172-16-12-…...
易泊车牌识别:海外车牌快速定制,开启智能识别新时代
在当今数字化快速发展的时代,车牌识别技术已经成为了智能交通系统中不可或缺的一部分。而在众多车牌识别解决方案中,易泊车牌识别系统以其卓越的性能和独特的优势脱颖而出,尤其是在海外车牌快速定制方面,更是展现出了强大的实力。…...
同一个交换机不同vlan的设备为什么不能通信
在同一个交换机上,不同 VLAN 的设备不能直接通信,这是因为 VLAN(虚拟局域网)通过在数据链路层(OSI 第2层)对设备进行逻辑隔离,将不同 VLAN 的设备视为属于不同的网络。具体原因如下:…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
