算法设计-搜索

一、BFS 模板

​ 如下所示

set<Node> visited;

bool check(Node son);

int bfs(Node start)
{
    // init
    queue<Node> q;
    q.push(start);
    visited.insert(start);
    
    while (!q.empty())
    {
        Node front = q.front();
     	q.pop();
        
        for (son : q.neigbour)
        {
            // prune
            if (check(son))
            {
             	q.push(son);
                visited.insert(son);
                // son is the correct answer
                if (ac(son))
                {
                    return son.info();
                }
            }
        }
    }
    
    return -1;
}

int main()
{
    //...
    int ans = bfs();
    //...
    return 0;
}

​ 其中有几部分需要一一强调,第一个是 check() 函数用于进行减枝,只有经过 check 的子节点会被加入队列。

bool check(Node son);

check 的基础内容就是有没有被 visited 过,其写法如下

visited.count(son) == 0 
visited.find(son) == visited.end()

​ 这两种写法都表明 visited 中没有 son

​ 另外就是有的时候 BFS 的遍历会伴随着诸多与 Node 对应的数据的记录,比如说每个 Node 对应的 level 这样的信息,建议使用一个(或者多个)全局的 map 去这样存储

map<Node, Info> levels;

​ 而一旦存在这样的 map,那么就可以省略 visited 了,因为没有必要了。判断是否存在,可以用

levels.count(son) == 0;
levels.find(son) == visited.end();

​ 同时当我们使用 BFS 的时候,我们一般是希望获得最优解(对应最小的 level),所以我们一般就遍历到合适的 Node ,就需要返回了,所以我们应当将 BFS 写成一个函数,然后方便 return 跑路。但是这就要求 BFS 需要的变量尽量是全局变量,方便访问。


二、双向 BFS

​ 其思想是,如果 BFS 的起点和终点是可以确定的,那么就分别从起点和终点进行 BFS,最终的判断条件是两棵树是否相交(本质是两个 visited 相交),这样做的好处是可以去掉大量的无用的遍历,同时保有了 BFS 的特性

​ 单向搜索:

在这里插入图片描述

​ 双向搜索:

在这里插入图片描述

​ 其在实现上基本上就是普通 BFS 复制一遍,唯一需要注意的就是利用 visit 相交的判断,板子题如下

[NOIP2002 提高组] 字串变换

题目描述

已知有两个字串 A , B A,B A,B 及一组字串变换的规则(至多 6 6 6 个规则),形如:

  • A 1 → B 1 A_1\to B_1 A1B1
  • A 2 → B 2 A_2\to B_2 A2B2

规则的含义为:在 A A A 中的子串 A 1 A_1 A1 可以变换为 $ B_1 , , A_2$ 可以变换为 B 2 ⋯ B_2\cdots B2

例如: A = abcd A=\texttt{abcd} A=abcd B = xyz B=\texttt{xyz} Bxyz

变换规则为:

  • abc → xu \texttt{abc}\rightarrow\texttt{xu} abcxu ud → y \texttt{ud}\rightarrow\texttt{y} udy y → yz \texttt{y}\rightarrow\texttt{yz} yyz

则此时, A A A 可以经过一系列的变换变为 B B B,其变换的过程为:

  • abcd → xud → xy → xyz \texttt{abcd}\rightarrow\texttt{xud}\rightarrow\texttt{xy}\rightarrow\texttt{xyz} abcdxudxyxyz

共进行了 3 3 3 次变换,使得 A A A 变换为 B B B

输入格式

第一行有两个字符串 A , B A,B A,B

接下来若干行,每行有两个字符串 A i , B i A_i,B_i Ai,Bi,表示一条变换规则。

输出格式

若在 10 10 10 步(包含 10 10 10 步)以内能将 A A A 变换为 B B B,则输出最少的变换步数;否则输出 NO ANSWER!

样例 #1

样例输入 #1

abcd xyz
abc xu
ud y
y yz

样例输出 #1

3

提示

对于 100 % 100\% 100% 数据,保证所有字符串长度的上限为 20 20 20

【题目来源】

NOIP 2002 提高组第二题

此时的题解如下

#include <bits/stdc++.h>

using namespace std;

string a[10], b[10];

int main()
{
    string origin, target;
    cin >> origin >> target;
    // 不定长输入
    int n = 0;
    while (cin >> a[n] >> b[n])
    {
        n++;
    }

    // 分别代表两个队列,分别从 up 和 down 两个方向搜索
    queue<string> up, down;
    // 记录字符串和步数的关系,同时兼具 visit 的功能
    map<string, int> upStep, downStep;
    // 入队起始节点,并登记
    up.push(origin);
    upStep[origin] = 0;
    down.push(target);
    downStep[target] = 0;
    // 搜索的次数最多是 10 次,所以双向 5 次
    for (int step = 1; step <= 5; step++)
    {
        // 先进行 up 向下搜索
        // 限制当前处理的都是 step - 1 层
        while (upStep[up.front()] == step - 1)
        {
            string front = up.front();
            up.pop();

            // 遍历所有的转换规则
            for (int i = 0; i < n; i++)
            {
                // 寻找所有位置的 a[i] 进行替换,pos 是可替换字符串子串出现的位置
                for (int pos = front.find(a[i]); pos != -1; pos = front.find(a[i], pos + 1))
                {
                    // tmp 是利用 a[i] -> b[i] 规则的字符串
                    string tmp = front;
                    // replace(pos, len, str) 从 pos 开始替换 len 长度的 str
                    tmp.replace(pos, a[i].length(), b[i]);
                    // 当 find 找不到的时候,会返回 end() 迭代器,此时说明没有 visitUp
                    if (upStep.find(tmp) == upStep.end())
                    {
                        // 入队
                        up.push(tmp);
                        // 登记
                        upStep[tmp] = step;
                    }
                    // 在对面找到了,所以一共花了 step * 2 - 1 步
                    if (downStep.find(tmp) != downStep.end())
                    {
                        // 搜出答案就可以结束了,从这里可以看,最好把 bfs 写成一个单独的函数,否则会非常丑陋
                        cout << step * 2 - 1;
                        return 0;
                    }
                }
            }
        }

        // down 向上搜索
        while (downStep[down.front()] == step - 1)
        {
            string front = down.front();
            down.pop();

            // 遍历所有的转换规则
            for (int i = 0; i < n; i++)
            {
                // 寻找所有位置的 b[i] 进行替换,pos 是可替换字符串子串出现的位置
                for (int pos = front.find(b[i]); pos != -1; pos = front.find(b[i], pos + 1))
                {
                    // tmp 是利用 b[i] -> a[i] 规则的字符串
                    string tmp = front;
                    // b[i] -> a[i]
                    tmp.replace(pos, b[i].length(), a[i]);
                    // 当 find 找不到的时候,会返回 end() 迭代器,此时说明没有 visitUp
                    if (downStep.find(tmp) == downStep.end())
                    {
                        down.push(tmp);
                        downStep[tmp] = step;
                    }
                    if (upStep.find(tmp) != upStep.end())
                    {
                        cout << step * 2;
                        return 0;
                    }
                }
            }
        }
    }

    cout << "NO ANSWER!";

    return 0;
}

​ 需要注意的是,这里用了固定迭代次数来进一步减枝,但是这并不是 BFS 的必要特征。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL教程——基础篇

MySQL教程MySQL教程——基础篇MySQL概述关系型数据库数据模型SQLSQL通用语法SQL数据类型SQL分类DDLDMLDQL基本查询条件查询聚合函数分组查询排序查询分页查询案例训练执行顺序DCL用户管理权限控制函数字符串函数数值函数日期函数流程函数约束概述约束演示外键约束添加外键删除外…

【ChatGPT】ChatGPT 能否取代程序员?

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 前言: ChatGPT 的优势 自然语言的生成 文本自动生成 建立了更人性化的人机交互 ChatGPT 的局限性 算法的解释能力较差 程序的可实现性较差 缺乏优化和质量控制 程序员相较于 …

Spring框架核心功能手写实现

文章目录概要Spring启动以及扫描流程实现基础环境搭建扫描逻辑实现bean创建的简单实现依赖注入实现BeanNameAware回调实现初始化机制模拟实现BeanPostProcessor模拟实现AOP模拟实现概要 手写Spring启动以及扫描流程手写getBean流程手写Bean生命周期流程手写依赖注入流程手写Be…

乐鑫 ESP-IoT-Bridge 方案支持设备灵活入网

观看视频了解 ESP-IoT-Bridge 联网方案乐鑫科技推出 ESP-IoT-Bridge 联网方案&#xff0c;能够为物联网应用场景下的 Wi-Fi、蓝牙、Thread、以太网、MCU 等设备&#xff0c;提供便捷的网络服务。 ESP-IoT-Bridge 以乐鑫 SoC 为载体&#xff0c;通过实现各类网络接口&#xff08…

Java文件IO

目录 一. 文件路径 1.1 绝对路径 1.2 相对路径 二 . 文件操作 2.1 File类 2.2 字符流 Reader/Writer 2.3 字节流 InputStream/OutputStream 三. 实现一个文件的搜索功能 一. 文件路径 1.1 绝对路径 从盘符开始&#xff0c;一层一层往下找&#xff0c;得到的路径是绝对路…

nvm管理node版本粗及

步骤一&#xff1a;清理本地node cmd ——> where node ——> 删除对应文件夹下所有node.exe的父文件夹控制面板 ——> 卸载node步骤二&#xff1a;安装nvm Tags coreybutler/nvm-windows GitHub 下载解压后运行安装exe文件&#xff0c;安装完成后重新cmd打开命令…

Hive3.1.3安装及部署

目录 1 下载地址 2 安装部署 2.1 安装Hive 2.2 启动并使用Hive 2.3 MySQL安装 2.3.1 安装MySQL 2.3.2 配置MySQL 2.3.3 卸载MySQL说明 2.4 配置Hive元数据存储到MySQL 2.4.1 配置元数据到MySQL 2.4.2 验证元数据是否配置成功 2.4.3 查看MySQL中的元数据 2.5 Hive服…

中金支付经历了4个月完成主要出资人前置审批

2023年4月6日&#xff0c;中国人民银行公示了关于中金支付有限公司的《中国人民银行准予行政许可决定书》&#xff08;银许准予决字〔2023〕第41号&#xff09;&#xff0c;同意中金支付有限公司主要出资人由中金金融认证中心有限公司变更为广州广电运通金融电子股份有限公司&a…

Nacos安全性探究

Nacos怎么做安全校验的&#xff1f; 以下使用nacos2.x 如上图所示&#xff0c; 可以直接访问Nacos的接口来获取用户列表。这说明Nacos的接口被爆露&#xff0c;任何情况下都可以访问&#xff0c;因此安全性得不到保障。 Nacos 使用 spring security 作为安全框架。spring sec…

【Mybatis】1—前言日志框架

⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记链接&#x1f449;https://github.com/A-BigTree/Code_Learning ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个star~&#x1f60a; 如果文章对你有所帮助&#xff0c;可以点赞&#x1f44d;…

RBF-UKF径向基神经网络结合无迹卡尔曼滤波估计锂离子电池SOC(附MATLAB代码)

目录 RBFNN训练结果 UKF估计SOC 文章的结尾红色部分有彩蛋 RBFNN训练结果 这篇文章主要介绍如何使用RBF神经网络训练出的参数并结合UKF算法完成锂离子电池SOC的估计&#xff0c;有关RBF参数训练过程的代码分析放在2天后的下一篇文章&#xff0c;这里只给出训练完成后的结果…

关于async/await、promise和setTimeout执行顺序

关于async/await、promise和setTimeout执行顺序 async function async1() {console.log(async1 start);await async2();console.log(asnyc1 end); } async function async2() {console.log(async2); } console.log(script start); setTimeout(() > {console.log(setTimeOut…

springboot(01)项目搭建与启动

01&#xff0c;项目搭建与启动 一&#xff0c;项目搭建 有多种方式可以搭建Spring Boot项目&#xff0c;包括&#xff1a; 使用Spring Boot CLI命令行工具使用Spring Initializr网站或IDE插件生成项目模板使用Maven或Gradle手动配置项目 每种方式都有其优缺点&#xff0c;具…

Android IPC Binder机制学习(一)

一、多进程系统设计及意义Android系统分为5层&#xff0c;不过Android一般岗位只关注上三层就够用了即&#xff1a;应用层、framework层、native层。Android中的应用层和系统服务层不在同一个进程&#xff0c;系统服务在单独的进程中。Android中不同的应用属于不同的进程中Andr…

ChatGPT遭禁用、抵制后又停止Plus付费发生了?

ChatGPT相关信息 2023年2月27日消息&#xff0c;Snapchat 正在推出一个基于 OpenAI 的 ChatGPT 最新版本的聊天机器人。 这款名为“My AI”的机器人将被固定在应用界面的聊天选项卡上&#xff0c;虽然最初仅适用于每月3.99美元的SnapchatPlus付费订阅用户&#xff0c;但最终目…

图像分类综述

一、图像分类介绍 什么是图像分类&#xff0c;核心是从给定的分类集合中给图像分配一个标签的任务。实际上&#xff0c;这意味着我们的任务是分析一个输入图像并返回一个将图像分类的标签。标签来自预定义的可能类别集。 示例&#xff1a;我们假定一个可能的类别集categories …

Vue3+vite2 博客前端开发

Vue3vite2 博客前端开发 文章目录Vue3vite2 博客前端开发前言页面展示代码设计卡片设计背景&#xff08;Particles.js粒子效果&#xff09;右侧个人信息与公告内容页友链总结前言 大家是否也想拥有一个属于自己的博客&#xff1f;但是如何去开发博客&#xff0c;怎样去开发一个…

毫升 | 主成分分析(PCA)

这种方法是由Karl Pearson 介绍的。它的工作条件是&#xff0c;当高维空间中的数据映射到低维空间中的数据时&#xff0c;低维空间中数据的方差应最大。 主成分分析 (PCA) 是一种用于降低大型数据集维数的统计技术。它是机器学习、数据科学和其他处理大型数据集的领域中常用的…

如何通过C++ 将数据写入 Excel 工作表

直观的界面、出色的计算功能和图表工具&#xff0c;使Excel成为了最流行的个人计算机数据处理软件。在独立的数据包含的信息量太少&#xff0c;而过多的数据又难以理清头绪时&#xff0c;制作成表格是数据管理的最有效手段之一。这样不仅可以方便整理数据&#xff0c;还可以方便…

aspnet030高校学生团体管理系统sqlserver

net030高校学生团体管理系统 . 1.用户基本信息管理模块&#xff1a;录入、修改、删除、查询、统计、打印等功能 2.学生成绩管理模块&#xff1a;录入、修改、删除、查询、统计、打印等功能 3.学生团体信息管理模块&#xff1a;录入、修改、删除、查询、统计、打印等功能 4.教…