第五十二章 BFS进阶(二)——双向广搜

news/2024/7/7 20:22:02

第五十二章 BFS进阶(二)——双向广搜

  • 一、双向广搜
    • 1、优越之处
    • 2、实现逻辑
    • 3、复杂度分析
  • 二、例题
    • 1、问题
    • 2、分析
    • 3、代码

一、双向广搜

1、优越之处

双向广搜是指我们从终点和起点同时开始搜索,当二者到达同一个中间状态的时候,即相遇。

那么这么搜有什么好处呢?

我们知道,在很多题目中,我们使用BFS的时间复杂度是指数级别的。

也就是说,如果讲BFS的进行次数画成一个函数的话,就会画成下面这个图。

在这里插入图片描述

如果我们采取从两端出发,到中间某点相遇的做法。

那么示意图可以画成下面的样子:
在这里插入图片描述

可能原来我们需要进行A次搜索,但是双向广搜的话,我们就只需要进行B次搜索。(上图仅仅表示一个大概意思,目的仅仅为了突出双向广搜进行了很大的优化,请勿追究细节)

除了上面这种大致的表示方法外,我们还可以画成一个搜索树的形式来看。

在这里插入图片描述
红色绿色线交叉的部分组成的菱形是双向广搜过程中所需搜索的状态数量。

上面的两个图仅仅是感性的分析了一下,双向广搜的优越之处。

我们还需要量化计算一下,到底优化了多少,具体的时间复杂度是多少,在分析复杂度之前,我们需要先看一下双向广搜大体的实现逻辑。

2、实现逻辑

我们创建两个队列。

一个队列从起点开始广搜,一个队列从终点开始广搜。

而在BFS中,我们的执行次数和队列中的元素是相关的。我们队列中的元素越多,BFS需要扩展的就越多。所以我们可以通过队列中的元素个数来代表一个BFS扩展时的复杂程度。

因此,我们可以比较两个BFS的队列中的元素,谁队列中元素少,就对哪个BFS进行拓展。

3、复杂度分析

根据上面的算法实现,我们可以知道,基本上就是从终点开始的BFS和从起点开始的BFS轮流进行。

我们可以认为二者进行的次数是一样的。

假设二者一共扩展了 K K K次,那么各自可以认为进行了 k / 2 k/2 k/2次。

这里的拓展是只刚才搜索树中的。假设每次扩展是多两个状态入队,那么总共的状态就是 1 + 2 1 + 2 2 . . . . + 2 k / 2 − 1 1 + 2^1 + 2^2 ....+2^{k/2-1} 1+21+22....+2k/21,求和以后约等于 2 k / 2 2^{k/2} 2k/2,那么两个BFS加起来就是 2 k / 2 + 1 2^{k/2+1} 2k/2+1

如果单向广搜的话,按照刚才的求和公式,对 k k k层的状态求和,大概是 2 k 2^{k} 2k

那么我们就发现优化了大约 2 k / 2 2^{k/2} 2k/2倍。

二、例题

1、问题

在这里插入图片描述

2、分析

过程很简单,就是从起点开始枚举每一个可能的变化,直到最后变成了B。

由于我们已经知道了终点过程,所以可以同时从B到A开始变化。一直到二者中间状态重合。

3、代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 6;
int n;
string A, B;
string a[N], b[N];
int extend(queue<string>& q, unordered_map<string, int >&da,unordered_map<string, int>&db,string a[N], string b[N])
{
	int d = da[q.front()];
	while(q.size() && da[q.front()] == d)
	{
		auto t = q.front();
		q.pop();

		for(int i = 0; i < n; i ++ )
		{
			for(int j = 0; j < t.size(); j ++ )
			{
				if(t.substr(j, a[i].size()) == a[i])
				{
					string r = t.substr(0, j) + b[i] + t.substr(j + a[i].size());
					if(db.count(r))return da[t] + db[r] + 1;
					if(da.count(r))continue;
					da[r] = da[t] + 1;
					q.push(r);
				}
			}
		}
	}
	return 11;
}
int bfs()
{
	if(A == B)return 0;
	queue<string>qa, qb;
	unordered_map<string, int> da, db;
	qa.push(A), qb.push(B);
	da[A] = db[B] = 0;
	int step = 0;
	while(qa.size() && qb.size())
	{
		int t;
		if(qa.size() < qb.size())
		{
			t = extend(qa, da, db, a, b);
		}
		else
		{
			t = extend(qb, db, da, b, a);
		}
		if(t <= 10)return t;
		if(++step == 10)return -1;
	}
	return -1;
}


void solve()
{
	cin >> A >> B;
	while(cin >> a[n] >> b[n])n ++;
	int t = bfs();
	if(t == -1)cout << "NO ANSWER!\n";
	else cout << t << "\n";
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	solve();
}

http://lihuaxi.xjx100.cn/news/873258.html

相关文章

【MT7628】MT7628如何修改串口波特率、调试串口物理口、使用UART3口

环境说明 sdk版本:Mediatek_ApSoC_SDK_4320_20150414.tar.bz2 芯片方案:MT7628A Uboot修改串口波特率方法 修改rt2880.h文件 修改include/configs/rt2880.h文件CONFIG_BAUDRATE宏的值 - #define CONFIG_BAUDRATE 57600 +#define CONFIG_BAUDRATE 115200 Kernel中修改串口波特…

学习英语的诀窍

学习英语有很多方法&#xff0c;以下是一些诀窍&#xff1a; 多读、多写&#xff1a;多读英语文章、诗歌、小说等&#xff0c;多写日记、邮件、作文等。 关注语音语法&#xff1a;注意发音&#xff0c;练习语法&#xff0c;提高语言表达能力。 观察原版影视剧&#xff1a;观察…

【设计模式-11】责任链模式

认识设计模式&#xff08;十一&#xff09;---责任链模式【一】责任链模式【二】介绍&#xff08;1&#xff09;意图&#xff08;2&#xff09;主要解决&#xff08;3&#xff09;何时使用&#xff08;4&#xff09;如何解决&#xff08;5&#xff09;关键代码&#xff08;6&am…

【openGauss实战9】深度分析分区表

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

centos学习记录

遇到的问题及其解决办法 centos7安装图形化界面 yum groupinstall ‘X Window System’ yum groupinstall -y ‘GNOME Desktop’ 安装完成后输入init 5进入图形化界面 centos7安装vmware-tools 第一步卸载open-vm-tools 输入命令 yum remove open-vm-tools 输入命令 reboot 在…

全网详细解读基于java调用ChatGPT的API接口

文章目录1. 文章引言2. 基于java调用API2.1 环境配置2.2 编写代码3. 重要总结3.1 官网链接地址3.2 开发语言的示例链接1. 文章引言 首先&#xff0c;我们需要访问ChatGPT的官网&#xff0c;官网提供了很多调用ChatGPT的API接口的语言示例&#xff0c;比如java&#xff0c;go&a…

2023 十大科技趋势发布

达摩院(The Academy for Discovery, Adventure, Momentum and Outlook,Alibaba DAMO Academy),阿里巴巴集团下属研发机构。成立于 2017 年 10 月 11 日,是一所致力于开展基础科学和颠覆式技术创新研究,以人类愿景为驱动力的企业驱动型 " 新型研发机构 ",立足基…

添加万位分隔符

问题:为数值添加万位分隔符 函数公式解决:=TEXT(A1,0&REPT("!,0000",LEN(INT(A1))/4.1)&".00")Len(Int(A1))/4.1,是一种为省字符而取巧的写法,正经写法是(Len(Int(A1))-1)/4,目的是为让结果与位数关联:4位及以内的整数部分为0;5-8位的整数…