双向广搜 bfs进阶 open the lock——hdu1195

目录

前言

   传统bfs

    双向广搜

open the lock

   问题描述

   输入

   输出

问题分析

   状态转变

   去重

单向搜索的bfs

双向广搜

   结束条件

   输出步数


前言

        其实这题数据不算复杂,不用双向广搜也可以完成,仅仅是为了更直观展现双向广搜的编码方式。

   传统bfs

        bfs向来都是搜索问题的一把好手,但一直以来bfs都有一个痛点,就是随着bfs层数的增加,bfs所要入队的元素一般会增长很快,有时的指数形,去重做的比较好那就是线性增长,但如果数据庞大是,这个数量依旧惊人

                       (线性增长)                                                  (指数增长)         

    双向广搜

        如果我们已知起点和终点,分别从起点和终点出发,那么就可以减少大量的状态数量

总结一点,如果去重都无法减少庞大的状态数量,那么就可以考虑双向广搜

open the lock

   问题描述

        有一个密码锁,总共四位数字,现已知四位数字的初始状态,和开锁密码,求最少几步可以开锁,密码锁上可以进行的操作,对于密码锁上的任意一位数字,都可以加一或减一,但如果数字原先为9,加一后为1,数字原先为1,减一后为9,也可以和该数字相邻的数字交换位置,最后一位数字和第一位数字不相邻,每次操作算一步

   输入

        第一行输入一个整数代表有多个测试,对于每个测试每行输入两个四位数,分别代表起始数字和密码锁密码

   输出

        对于每个测试,输出一个整数,代表所花费的最少步数

问题分析

        本题其实没有特别的难点,最主要的就是处理四位数之间状态的转变

   状态转变

        我使用了一个函数来封装这个转变:

string Skip(string& ss, int i, int j) {//注:字符-'0' 字符变数字,数字+'0' 数字变字符/*i:操作目标四位数的位数j:操作方法ss:目标四位数*/int m;if (j == 1) {m = ss[i] - '0' + 1;if (m == 10) m = 1;ss[i] = m + '0';}if (j == 2) {m = ss[i] - '0' - 1;if (m == 0) m = 9;ss[i] = m + '0';}if (j == 3 && i <= 2) { //j<=2,最后一位数字不交换,其实也不是说不交换,就是我们只考虑单项交换,所以最后一位数字相当于不交换,其实他还是可以和他的前一位数字交换的,只是发起交换的对象不是它Swap(ss, i);}return ss;
}

        值得一提的是交换操作,最后一位数字不交换,其实也不是说不交换,就是我们只考虑单项交换,所以最后一位数字相当于不交换,其实他还是可以和他的前一位数字交换的,只是发起交换的对象不是它

   去重

        这里我使用的是map去重,也可以用set去重,详情请看bfs与判重

单向搜索的bfs

        其实本题单向搜索就可以完成了,因为判重操作后,每次进队的数量不会超过9999-1111,不算多,所以也可以通过:

#include<iostream>
#include<queue>
#include<map>
using namespace std;string st, ed;struct node {string s;int step;node(){}node(string ss,int st):s(ss),step(st){}
};node now, nxt;
queue<node>que;
map<string, bool>mp;void Swap(string& ss, int i) {char tmp = ss[i];ss[i] = ss[i + 1];ss[i + 1] = tmp;
}string Skip(string& ss,int i,int j) {int m;if (j == 1) {m = ss[i] - '0' + 1;if (m == 10) m = 1;ss[i] = m + '0';}if (j == 2) {m = ss[i] - '0' - 1;if (m == 0) m = 9;ss[i] = m + '0';}if (j == 3 && i<=2) {Swap(ss, i);}return ss;
}void bfs() {que.push(node(st, 0));mp[st] = true;while (!que.empty()) {now = que.front();que.pop();for (int i = 0; i < 4; i++) {  //交换操作或数值改变操作for (int j = 1; j <= 3; j++) {nxt.s = now.s;  //这个注意一下,每次修改都是在now.s的基础上该nxt.s = Skip(nxt.s, i, j);if (nxt.s == ed) {cout << nxt.s << endl;cout << now.step+1 << endl;return;}if (!mp[nxt.s]) {cout << nxt.s << endl;nxt.step = now.step + 1;que.push(node(nxt));mp[nxt.s] = true;}}}}
}int main() {int test;cin >> test;while (test--) {cin >> st;cin >> ed;//cout << st << ed;if (st == ed) {cout << 0 << endl;continue;}mp.clear();bfs();}
}

双向广搜

        使用双向广搜,可以减少一次进入队列的状态数量,也是个不错的算法

   结束条件

        单向搜索的结束条件可以根据是否到达终点判断,当时双向搜索是在中途就已经结束了,所以还需要对结束条件进行讨论

        我们定义了两个map,如果找到一个位置,两个map都已经搜过,那么这个点就是相遇点,结束搜索。

   输出步数

        单向搜索的输出很简单,只需要输出now.step即可,但是双向搜索显然不行,因为两个now节点不一定同时指向同一个四位数,所以还需要一个dis数组保存步数

        接下来就可以编写代码了(这里我使用双队列的双向广搜)

#include<iostream>
#include<queue>
#include<map>
using namespace std;string st, ed;struct node {string s;int step;node() {}node(string ss, int st) :s(ss), step(st) {}
};node nowa, nxta;
node nowb, nxtb;;
queue<node>qa;  //从起点开始搜
queue<node>qb;  //从终点开始搜
map<string, bool>mp1;   //起点队列判重
map<string, bool>mp2;   //终点队列判重
map<string, int>dis;    //记录距离void Swap(string& ss, int i) {//其实交换操作可以看成是单向的,因为双向和单向结果没区别char tmp = ss[i];ss[i] = ss[i + 1];ss[i + 1] = tmp;
}string Skip(string& ss, int i, int j) {//注:字符-'0' 字符变数字,数字+'0' 数字变字符int m;if (j == 1) {m = ss[i] - '0' + 1;if (m == 10) m = 1;ss[i] = m + '0';}if (j == 2) {m = ss[i] - '0' - 1;if (m == 0) m = 9;ss[i] = m + '0';}if (j == 3 && i <= 2) { //j<=2,最后一位数字不交换,其实也不是说不交换,就是我们只考虑单项交换,所以最后一位数字相当于不交换,其实他还是可以和他的前一位数字交换的,只是发起交换的对象不是它Swap(ss, i);}return ss;
}void bfs() {qb.push(node(ed, 0));qa.push(node(st, 0));dis[st] = 0;dis[ed] = 0;mp1[st] = true;mp2[ed] = true;while (!qa.empty() && !qb.empty()) {//保证起点和终点同步扩散if (qa.size() < qb.size()) {//起点nowa = qa.front();qa.pop();for (int i = 0; i < 4; i++) {  //交换操作或数值改变操作for (int j = 1; j <= 3; j++) {nxta.s = nowa.s;  //这个注意一下,每次修改都是在now.s的基础上该nxta.s = Skip(nxta.s, i, j);if (mp2[nxta.s] == true) {//cout << nxta.s << endl;cout << nowa.step + dis[nxta.s]+1 << endl; //注意这里要加1,因为起点和终点的step都是0return;}if (!mp1[nxta.s]) {//cout << nxta.s << endl;nxta.step = nowa.step + 1;qa.push(node(nxta));dis[nxta.s] = nxta.step;mp1[nxta.s] =true;}}}}else {//终点nowb = qb.front();qb.pop();for (int i = 0; i < 4; i++) {  //交换操作或数值改变操作for (int j = 1; j <= 3; j++) {nxtb.s = nowb.s;  //这个注意一下,每次修改都是在now.s的基础上该nxtb.s = Skip(nxtb.s, i, j);if (mp1[nxtb.s]==true) {cout << nowb.step +dis[nxtb.s]+1<< endl; return;}if (!mp2[nxtb.s]) {nxtb.step = nowb.step + 1;qb.push(node(nxtb));dis[nxtb.s] = nxtb.step;mp2[nxtb.s] = true;}}}}}
}int main() {int test;cin >> test;while (test--) {cin >> st;cin >> ed;if (st == ed) {cout << 0 << endl;continue;}bfs();//很多人喜欢用数组实现,但我还是倾向于用stl,更加简洁mp1.clear();mp2.clear();dis.clear();}
}

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

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

相关文章

通用文件I/O模型之open

前面介绍了linux系统一切皆文件的概念&#xff0c;系统使用一套系统调用函数open()、read()、write()、close()等可以对所有文件执行I/O操作。应用程序发起的I/O请求&#xff0c;内核会将其转化为相应的文件系统操作&#xff0c;或者设备驱动程序操作。接下来我们一起了解一下o…

电磁兼容(EMC):整改案例(五)EFT测试,改初级Y电容

目录 1. 异常现象 2. 原因分析 3. 整改方案 4. 总结 1. 异常现象 某产品按GB/T 17626.4标准进行电快速瞬变脉冲群测试&#xff0c;测试条件为&#xff1a;频率5kHz/100kHz&#xff0c;测试电压L&#xff0c;N线间2kV。其中频率5kHz时&#xff0c;测试通过&#xff0c;但频…

在Centos中安装、配置与使用atop监控工具

目录 前言1. atop工具的安装1.1 atop简介1.2 atop的安装步骤 2. 安装并配置netatop模块2.1 安装内核开发包2.2 安装所需依赖2.3 下载netatop2.4 解压并安装netatop2.5 启动netatop 3. atop的配置与使用3.1 配置监控周期与日志保留时间3.2 设置定时任务生成日志3.3 启动与查看at…

【2024年最新】基于springboot+vue的垃圾分类网站lw+ppt

作者&#xff1a;计算机搬砖家 开发技术&#xff1a;SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;Java精选实战项…

Facebook脸书投放目录guanggao(更适合独立站)操作步骤教学

Facebook guanggao是企业进行品牌推广、产品销售和营销转化的有效工具。在Facebook guanggao中创建目录可以帮助企业更好地展示产品&#xff0c;提高guanggao效果。以下是创建目录的详细步骤&#xff1a; 登录Facebook Business Manager&#xff08;BM业务管理器&#xff09;&a…

yolo 11从原理、创新点、训练到部署(yolov11代码+教程)

YOLO&#xff08;You Only Look Once&#xff09;系列模型以其高效的目标检测能力在计算机视觉领域取得了显著的成果。YOLOv11 作为 YOLO 系列的最新进展&#xff0c;进一步提升了模型的性能和实用性。本文将从 YOLOv11 的原理、创新点、训练到部署进行详细介绍&#xff0c;并附…

【写个本地的html】写个本地的html文件,做个demo,直接用浏览器打开

需求:需要给甲方发个html文件版本的demo,本地打开,如图所示 ui给了6张图片,写6个按钮点击更换背景图片 代码没写完,但是基础结构都有,供大家参考: 创建一个文件夹,用vscode打开,创建index.html index.html代码如下 <!DOCTYPE html> <html> <head&g…

【含开题报告+文档+PPT+源码】基于springBoot+vue超市仓库管理系统的设计与实现

开题报告 随着电子商务的快速发展和物流行业的日益壮大&#xff0c;超市仓库管理系统的重要性也日益凸显。传统的超市仓库管理方式存在许多问题&#xff0c;比如人工操作繁琐、数据统计不准确、管理效率低下等。因此&#xff0c;需要设计和实现一个高效、智能的超市仓库管理系…

Vite + Vue3 使用 cdn 引入依赖,并且把外部 css、js 文件内联引入

安装插件 pnpm i element-plus echarts axios lodash -S在 vite.config.js 引用 注意事项&#xff1a;element-plus 不能在 vite.config.js 中使用按需加载&#xff0c;需要在 main.js 中全局引入&#xff1b; import { resolve } from path import { defineConfig } from v…

.NET 回顾 | 一款反序列化漏洞的白名单工具

01阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&#xf…

Linux 安装 NVM 并配置 npm 加速,开发 node 项目不再愁

由于需要在 linux 机器上完成 node 项目的构建&#xff0c;需要安装 nodejs, 想着不同项目需要使用不同的版本&#xff0c;索性安装一下 nvm 吧&#xff0c;因为之前在 windows 上已经安装过 nvm-windows, 应该很容易上手&#xff0c;我尝试了官网提供的几种方式&#xff0c;最…

基于springboot vue在线学籍管理系统设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm 等开发框架&#xff09; vue .net php python(flask Django) 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找…

Nexpose 6.6.271 发布下载,新增功能概览

Nexpose 6.6.271 for Linux & Windows - 漏洞扫描 Rapid7 Vulnerability Management, release Sep 26, 2024 请访问原文链接&#xff1a;https://sysin.org/blog/nexpose-6/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.or…

RAG(Retrieval-Augmented Generation,检索增强生成)

简介&#xff1a;个人学习分享&#xff0c;如有错误&#xff0c;欢迎批评指正。 RAG&#xff08;Retrieval-Augmented Generation&#xff09;是一种结合信息检索与生成式模型的混合架构&#xff0c;旨在提升自然语言生成任务的准确性、丰富性和知识覆盖范围。它通过在生成过程…

基于SpringBoot+Vue的Cosplay交流论坛系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

【Java程序设计】动态规划算法专题(六):回文串问题

目录 1、回文子串&#xff08;"引子题"&#xff09; 1.1 算法原理 1.2 算法代码 2、最长回文子串 2.1 算法原理 2.2 算法代码 3、分割回文串 IV&#xff08;hard&#xff09; 3.1 算法原理 3.2 算法代码 4、分割字符串 II&#xff08;hard&#xff09; 4…

HAL库常用的函数:

目录 HAL库&#xff1a; 1.GPIO常用函数&#xff1a; 1.HAL_GPIO_ReadPin( ) 2.HAL_GPIO_WritePin( ) 3.HAL_GPIO_TogglePin( ) 4.HAL_GPIO_EXTI_IRQHandler( ) 5.HAL_GPIO_EXTI_Callback( ) 2.UART常用函数&#xff1a; 1.HAL_U…

深度学习笔记(持续更新)

注&#xff1a;本文所有深度学习内容都是基于PyTorch&#xff0c;PyTorch作为一个开源的深度学习框架&#xff0c;具有可以动态计算图、拥有简洁易用的API、支持GPU加速等特点&#xff0c;在计算机视觉、自然语言处理、强化学习等方面有广泛应用。 使用matplotlib绘图&#xff…

Python | Leetcode Python题解之第468题验证IP地址

题目&#xff1a; 题解&#xff1a; class Solution:def validIPAddress(self, queryIP: str) -> str:if queryIP.find(".") ! -1:# IPv4last -1for i in range(4):cur (len(queryIP) if i 3 else queryIP.find(".", last 1))if cur -1:return &q…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-10

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-10 1. Characterizing and Efficiently Accelerating Multimodal Generation Model Inference Y Lee, A Sun, B Hosmer, B Acun, C Balioglu, C Wang… - arXiv preprint arXiv …, 2024 https://arxiv.org/pdf…