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 的设备视为属于不同的网络。具体原因如下:…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
