题解 CodeForces 1037D Valid BFS? 三种解法 C++

题目传送门

Problem - 1037D - Codeforceshttps://codeforces.com/problemset/problem/1037/Dhttps://codeforces.com/problemset/problem/1037/Dhttps://codeforces.com/problemset/problem/1037/Dhttps://codeforces.com/problemset/problem/1037/Dhttps://codeforces.com/problemset/problem/1037/Dhttps://codeforces.com/problemset/problem/1037/Dhttps://codeforces.com/problemset/problem/1037/D

翻译

广度优先搜索(BFS)算法定义如下。

  1. 考虑一个无向图,顶点编号从 1 到 n。初始化 q 为一个新的队列,仅包含顶点 1,并将顶点 1 标记为已使用。
  2. 从队列 q 的头部提取一个顶点 v。
  3. 打印顶点 v 的索引。
  4. 以任意顺序遍历所有与 v 相邻且尚未标记为已使用的顶点 u。将顶点 u 标记为已使用,并将其插入到队列 q 的尾部。
  5. 如果队列不为空,从第 2 步继续。
  6. 否则结束。

由于选择每个顶点的邻居的顺序可以变化,因此可能存在多个序列可以被 BFS 打印。

在这个问题中,你需要检查给定的序列是否对应于从顶点 1 开始的给定树的某个有效 BFS 遍历。树 是一个无向图,任意两个顶点之间恰好有一条简单路径。

输入

第一行包含一个整数 n (1≤n≤2⋅10^5),表示树中的节点数量。

接下来的 n−1 行描述树的边。每行包含两个整数 x 和 y (1≤x,y≤n) — 对应边的两个端点。保证给定的图是树。

最后一行包含 n 个不同的整数 a1,a2,…,an​ (1≤ai≤n) — 要检查的序列。

输出

如果该序列对应于给定树的某个有效 BFS 遍历,则打印 "Yes"(引号仅为清晰),否则打印 "No"(引号仅为清晰)。

你可以使用任意大小写打印每个字母(大写或小写)。

示例

InputcopyOutputcopy
4
1 2
1 3
2 4
1 2 3 4
Yes
InputcopyOutputcopy
4
1 2
1 3
2 4
1 2 4 3
No

注意

两个示例测试中包含相同的树。

在这棵树中,有两个有效的 BFS 排序:

  • 1,2,3,4
  • 1,3,2,4

排序 1,2,4,3 不对应于任何有效的 BFS 排序。

解法

易错点解读

连续节点并非同层就行,还有一个重要的点是,子树顺序要与父节点顺序对应

如:1 2 3 [2 的子节点] [3 的子节点] 才行,1 2 3 [3 的子节点] [2 的子节点] 就不行

解法一览

1.按输入顺序生成 BFS 序列,比较输入序列与生成序列 (比较好理解)

2.循环模拟队列

1) for 循环模拟队列 (比较抽象,代码精简)

2) while 循环模拟队列 (有点抽象)

三种解法效率差不多,250~350ms (前提是经过优化且采用较快的 I/O 方式)

一、按输入顺序生成 BFS 序列,比较输入序列与生成序列

思路

BFS 序列可能有很多,根本原因如题目所说 "选择每个顶点的邻居的顺序可以变化"

即同层节点,入队的顺序有很多种

那我们可以按题目给出的序列重定义入队顺序,对于某节点的子节点

先在序列中出现,就先入队,比较生成的 BFS 序列与所给序列是否相同即可

细节见代码注释

代码

#include <algorithm>
#include <vector>
#include <cstdio>
using namespace std;
const int N = 200010;
vector<int> g[N];
int n, x, y, q[N], idx[N], ans[N], head, tail = -1; //q 是输入的队列,ans 是生成的队列,idx 是优先级
bool mk[N];
bool cmp(int a, int b) { return idx[a] < idx[b]; } //重定义入队优先级,先输入的就先入队
int main()
{scanf("%d", &n);for (int i = 1; i < n; i++){scanf("%d%d", &x, &y);g[x].push_back(y);g[y].push_back(x);}for (int i = 0; i < n; i++) scanf("%d", &q[i]), idx[q[i]] = i; //先输入的下标更小,更先入队if (idx[1] != 0) return puts("No") * 0; //需要特判第一个元素for (int i = 1; i <= n; i++) sort(g[i].begin(), g[i].end(), cmp); //按入队优先级对子节点排序ans[++tail] = 1; //生成队列初始化mk[1] = true;while (head <= tail){int t = ans[head++];for (auto z : g[t]){if (mk[z] == false) //因为是无向边,子节点可以通向父节点,为避免父节点入队子节点后子节点又入队父节点,开标记数组,入队过就不再入队了{ans[++tail] = z;if (q[tail] != ans[tail]) return puts("No") * 0; //两个序列有任何差异都输出 Nomk[z] = true;}}}return puts("Yes") * 0; //无差异输出 Yes
}

二、for 循环模拟队列

思路

根据输入的节点序列,用 for 循环模拟队列

设节点序列为 node[N],队首为 head,队尾为 tail

和一般队列不同的是,在此处 tail 指向下一个要入队的节点

也就是指向当前真正的队尾的下一个节点

每轮循环的任务:入队队首的所有子节点,然后队首出队

对于合法的 BFS 序列,每次循环体执行前

从 tail 开始的向后的一片连续节点都来自同一层,且子树顺序与父节点顺序对应

核心代码

int tail = 1; //tail 指向下一个要入队的节点,1 已经入队了,所以 tail 从 1 开始
for (int head = 0; head < n; head++)
while (node[head]、node[tail] 之间存在边) tail++;
printf("%s", node[0] == 1 && tail == n ? "Yes" : "No");

输入的节点序列但凡有一处不满足 BFS 序列的要求

node[head]、node[tail] 之间就不存在边,tail 就会卡住不动而不能到达 n

理解这点是理解这种思路的关键

细节

注意第一个节点一定要是 1,需要特判

无论节点序列是否是合法的 BFS 序列,都能够保证先入队的节点深度不大于后入队的节点
因为保证了第一个节点一定是 1,后续节点都是从前向后扩展出来的
因此入队时只需要判断两节点之间是否存在边,而不需要判断父子关系

怎么高效地判断两节点之间边的存在性?

邻接矩阵存不下 (200000)^2,要用邻接表,且邻接表中的子数据结构用 set,而不是 链表/vector

因为 链表/vector 查询特定边的效率较低。set 就比较合适

因为所有边的边权都是相同的,所以不用 map

虽然没有排序的需求,但 set 有时其实更快

实测本题 unordered_set 效率略低于 set,前者优化后约 500ms,后者优化后约 300ms

优化

循环条件可以加上 head < tail,这是队列的性质,队首不能超过队尾
节点序列不是合法的 BFS 序列时,tail 就会卡住不动,导致 head 超过 tail,提前终止循环
为什么不是 <=,因为 tail 在此处的含义和一般队列不同,指向下一位

当然 head <= tail 也不会 WA

代码

#include <set>
#include <cstdio>
using namespace std;
const int N = 200010;
set<int> g[N];
int n, node[N];
int main()
{scanf("%d", &n);for (int i = 1; i < n; i++){int x, y;scanf("%d%d", &x, &y);g[x].insert(y);g[y].insert(x);}for (int i = 0; i < n; i++) scanf("%d", &node[i]);if (node[0] != 1) return puts("No") * 0;int tail = 1;for (int head = 0; head < n && head < tail; head++)while (g[node[head]].count(node[tail])) tail++;return puts(tail == n ? "Yes" : "No") * 0;
}

三、while 循环模拟队列

思路

一种写法是,预处理得到每个节点子节点的数量,作为队首出队依据

每次循环,入队下一个元素,然后循环判断当前队首是否应该出队

(计数变量统计当前队首已入队的子节点的数量,达到预处理统计结果就出队并重置计数变量)

执行完上述两步后,再判断当前入队的元素是否是当前队首的子节点

如果是,计数变量++,如果不是,输出 No

循环执行期间没输出过 No,就输出 Yes

我一开始写的就是这种,感觉理论上是可行的

但是不知道为什么,测试点 11 死活过不去,就鸽了

感兴趣可以写写看。while 循环模拟队列,应该也不止这一种写法

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024微短剧行业生态洞察报告汇总PDF洞察(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p39072 本报告合集洞察从多个维度全面解读微短剧行业。在行业发展层面&#xff0c;市场规模与用户规模双增长&#xff0c;创造大量高收入就业岗位并带动产业链升级。内容创作上&#xff0c;精品化、品牌化趋势凸显&#xff0c;题材走…

HTML<img>标签

例子 如何插入图片&#xff1a; <img src"img_girl.jpg" alt"Girl in a jacket" width"500" height"600"> 下面有更多“自己尝试”的示例。 定义和用法 该<img>标签用于在 HTML 页面中嵌入图像。 从技术上讲&#x…

故障诊断 | BWO白鲸算法优化KELM故障诊断(Matlab)

目录 效果一览文章概述BWO白鲸算法优化KELM故障诊断一、引言1.1、研究背景及意义1.2、故障诊断技术的现状1.3、研究目的与内容二、KELM基本理论2.1、KELM模型简介2.2、核函数的选择2.3、KELM在故障诊断中的应用三、BWO白鲸优化算法3.1、BWO算法基本原理3.2、BWO算法的特点3.3、…

apisix的authz-casbin

目录 1、apisix的auth-casbin官方介绍 2、casbin介绍和使用 2.1基本知识&#xff1a; 2.2使用例子 3、配置插件 4、postman调用 5、auth-casbin的坑 1、apisix的auth-casbin官方介绍 authz-casbin | Apache APISIX -- Cloud-Native API Gateway 2、casbin介绍和使用 c…

基于python+Django+mysql鲜花水果销售商城网站系统设计与实现

博主介绍&#xff1a;黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者&#xff0c;CSDN博客专家&#xff0c;在线教育专家&#xff0c;CSDN钻石讲师&#xff1b;专注大学生毕业设计教育、辅导。 所有项目都配有从入门到精通的基础知识视频课程&#xff…

【大模型】ChatGPT 高效处理图片技巧使用详解

目录 一、前言 二、ChatGPT 4 图片处理介绍 2.1 ChatGPT 4 图片处理概述 2.1.1 图像识别与分类 2.1.2 图像搜索 2.1.3 图像生成 2.1.4 多模态理解 2.1.5 细粒度图像识别 2.1.6 生成式图像任务处理 2.1.7 图像与文本互动 2.2 ChatGPT 4 图片处理应用场景 三、文生图操…

【0x0052】HCI_Write_Extended_Inquiry_Response命令详解

目录 一、命令概述 二、命令格式及参数 2.1. HCI_Write_Extended_Inquiry_Response命令格式 2.2. FEC_Required 2.3. Extended_Inquiry_Response 三、生成事件及参数 3.1. HCI_Command_Complete 事件 3.2. Status 四、命令执行流程 4.1. 命令准备阶段(主机端) 4.2…

函数递归的介绍

1.递归的定义 在C语言中&#xff0c;递归就是函数自己调用自己 上面的代码就是 main 函数在函数主体内 自己调用自己 但是&#xff0c;上面的代码存在问题&#xff1a;main 函数反复地 自己调用自己 &#xff0c;不受限制&#xff0c;停不下来。 最终形成死递归&#xff0c;…

小白爬虫——selenium入门超详细教程

目录 一、selenium简介 二、环境安装 2.1、安装Selenium 2.2、浏览器驱动安装 三、基本操作 3.1、对页面进行操作 3.1.1、初始化webdriver 3.1.2、打开网页 3.1.3、页面操作 3.1.4、页面数据提取 3.1.5、关闭页面 ?3.1.6、综合小案例 3.2、对页面元素进行操作 3…

JDK长期支持版本(LTS)

https://blogs.oracle.com/java/post/the-arrival-of-java-23 jdk长期支持版本&#xff08;LTS&#xff09;&#xff1a;JDK 8、11、17、21&#xff1a;

三格电子——MODBUS TCP 转 CANOpen 协议网关

一、产品概述 1.1 产品用途 SG-TCP-COE-210 网关可以实现将 CANOpen 接口设备连接到 MODBUS TCP 网络中。用户不需要了解具体的 CANOpen 和 Modbus TCP 协议即可实现将 CANOpen 设备挂载到 MODBUS TCP 接口的 PLC 上&#xff0c;并和 CANOpen 设备进行 数据交互。 1.2 产品…

在离线无管理员权限的情况下为Linux配置oh-my-zsh(zsh+oh my zsh+powerlevel10k)

0. 前言 最近接触到一台离线环境下的Linux&#xff08;CentOS7&#xff09;&#xff0c;自带的终端实在过于丑陋&#xff08;tcsh&#xff09;&#xff0c;但是搜半天改zsh的教程要么要网、要么要管理员权限&#xff0c;奋而自己折腾半天记录于此以作备忘。 所需环境 一台能…

C 语言雏启:擘画代码乾坤,谛观编程奥宇之初瞰

大家好啊&#xff0c;我是小象٩(๑ω๑)۶ 我的博客&#xff1a;Xiao Xiangζั͡ޓއއ 很高兴见到大家&#xff0c;希望能够和大家一起交流学习&#xff0c;共同进步。* 这一课主要是让大家初步了解C语言&#xff0c;了解我们的开发环境&#xff0c;main函数&#xff0c;库…

Java - WebSocket

一、WebSocket 1.1、WebSocket概念 WebSocket是一种协议&#xff0c;用于在Web应用程序和服务器之间建立实时、双向的通信连接。它通过一个单一的TCP连接提供了持久化连接&#xff0c;这使得Web应用程序可以更加实时地传递数据。WebSocket协议最初由W3C开发&#xff0c;并于2…

C语言内存之旅:从静态到动态的跨越

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 本文目录 引言正文一 动态内存管理的必要性二 动态…

气膜料仓:工业仓储的高效与安全新选择—轻空间

在工业仓储领域&#xff0c;如何实现高效、安全、环保的存储方式成为企业关注的重点。气膜料仓以其独特的无梁无柱设计和智能化功能&#xff0c;为工业仓储带来了全新的解决方案。 空间利用率高&#xff1a;无障碍的大容量仓储 气膜料仓内部无梁无柱&#xff0c;形成了完全开…

Windows FileZila Server共享电脑文件夹 映射21端口外网连接

我有这样一个使用场景&#xff0c;在外部网络环境下&#xff0c;通过手机便捷地读取存储在电脑上的视频文件。比如在外出旅行、出差&#xff0c;身边没有携带电脑&#xff0c;仅依靠手机设备&#xff0c;就能随时获取电脑里存储的各类视频&#xff0c;无论是学习资料视频、工作…

CentOS部署FastDFS+Nginx并实现远程访问本地服务器中文件

文章目录 前言1. 本地搭建FastDFS文件系统 1.1 环境安装1.2 安装libfastcommon1.3 安装FastDFS1.4 配置Tracker1.5 配置Storage1.6 测试上传下载1.7 与Nginx整合1.8 安装Nginx1.9 配置Nginx 2. 局域网测试访问FastDFS3. 安装cpolar内网穿透4. 配置公网访问地址5. 固定公网地址…

2023年江西省职业院校技能大赛网络系统管理赛项(Linux部分样题)

一、Linux项目任务描述 你作为一个Linux的技术工程师,被指派去构建一个公司的内部网络,要为员工提供便捷、安全稳定内外网络服务。你必须在规定的时间内完成要求的任务,并进行充分的测试,确保设备和应用正常运行。任务所有规划都基于Linux操作系统,请根据网络拓扑、基本配…

【Spring】定义的Bean缺少隐式依赖

问题描述 初学 Spring 时&#xff0c;我们往往不能快速转化思维。例如&#xff0c;在程序开发过程中&#xff0c;有时候&#xff0c;一方面我们把一个类定义成 Bean&#xff0c;同时又觉得这个 Bean 的定义除了加了一些 Spring 注解外&#xff0c;并没有什么不同。所以在后续使…