CF1000E We Need More Bosses

CF1000E We Need More Bosses

题目描述

题目大意:

给定一个 n n n 个点 m m m 条边的无向图,保证图连通。找到两个点 s , t s,t s,t,使得 s s s t t t必须经过的边最多(一条边无论走哪条路线都经过ta,这条边就是必须经过的边), 2 < = n < = 3 ∗ 1 0 5 , 1 < = m < = 3 ∗ 1 0 5 2<=n<=3*10^5,1<=m<=3*10^5 2<=n<=3105,1<=m<=3105

输入格式

第一行两个整数, n , m n,m n,m

以下m行,每行两个整数 x , y x,y x,y,表示 x y xy xy间有一条无向边相连

输出格式

一个整数,即最多的必须经过边数

感谢@守望 提供翻译

输入输出样例 #1

输入 #1

5 5
1 2
2 3
3 1
4 1
5 2

输出 #1

2

输入输出样例 #2

输入 #2

4 3
1 2
4 3
3 2

输出 #2

3

思路:

求下边的双连通性,然后找一条必经的最长路(题目中写的 s s s t t t 必须经过的边最多),也就是求所有桥的数量。
最长路就是缩点后树的直径,所有的边都是桥,求一下桥的数量就是最多的必须经过边数。

T a r j a n Tarjan Tarjan 算法求 E D C C EDCC EDCC,套模板

inline void add(int a, int b) {e.push_back({b, h[a]});h[a] = e.size() - 1;
}void Tarjan(int u, int in_edge) {low[u] = dfn[u] = ++tot;stk.push(u);for(int i = h[u]; ~i; i = e[i].ne) {int v = e[i].v;if(!dfn[v]) {Tarjan(v, i);low[u] = std::min(low[u], low[v]);if(low[v] > dfn[u]) bri[i] = bri[i ^ 1] = true; // 下个点的最小时间戳比当前点的时间戳大, 说明是桥}else if(i != (in_edge ^ 1)) low[u] = std::min(low[u], dfn[v]); // 这条边不能是反向边}if(low[u] == dfn[u]) {int v;cnt++;do{v = stk.top();stk.pop();dcc[v] = cnt;}while(v != u);}
}

建立新的树:

    tree.resize(cnt + 1);Rep(u, 1, n + 1) {for(int i = h[u]; ~i; i = e[i].ne) {int v = e[i].v;if(bri[i]) { // 这条边是桥int nu = dcc[u], nv = dcc[v];if(nu == nv) continue; // 不能连接相同编号tree[nu].push_back(nv);tree[nv].push_back(nu);}}}

树的直径的求法:两段BFS,一段取任意一个点找到一个距离他最远的那个点 u u u ,然后在从 u u u 开始找,找到距离 u u u 最远的点 v v v ,这两个点之间的路径就是树的直径,也就是最长的距离 s − > t s -> t s>t

inline int BFS(int root) {dist.assign(cnt + 1, INF);q = std::queue<int>();int max_num = root, max_dist = 0;q.push(root);dist[root] = 0;while(!q.empty()) {int u = q.front();q.pop();for(const int& v : tree[u]) {if(dist[v] == INF) { // 没走过dist[v] = dist[u] + 1;if(dist[v] > max_dist) {max_dist = dist[v];max_num = v;}q.push(v);}}}return max_num;
}main:// 计算树的直径int u = BFS(1); // 这个点是任意的int v = BFS(u);

然后找一下从 u u u v v v 一共经过了多少边就是多少桥。

inline void BFS(int u, int v) { // 重载dist.assign(cnt + 1, INF);q = std::queue<int>();q.push(u);dist[u] = 0;while(!q.empty()) {int now = q.front();q.pop();for(const int& ne : tree[now]) {if(dist[ne] == INF) {dist[ne] = dist[now] + 1;q.push(ne);}}}std::cout << dist[v] << '\n';
}

T a r j a n + 树的直径 Tarjan + 树的直径 Tarjan+树的直径 A C c o d e : AC code: ACcode:

#include <iostream>
#include <climits>
#include <limits>
#include <vector>
#include <queue>
#include <stack>typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
typedef std::pair<int, int> PII;#define rep(i, n) for(int i = 0; i < n; i++)
#define Rep(i, len, n) for(int i = len; i < n; i++)
#define MAX_INT 0x7fffffff
#define MIN_INT 0x80000000const int INF = std::numeric_limits<int>::max();struct edge {int v, ne;
};int n, m, tot = 0, cnt = 0;
std::vector<edge> e;
std::vector<std::vector<int>> tree;
std::vector<int> low, dfn, bri, h, dcc, dist;
std::stack<int> stk;
std::queue<int> q;inline void add(int a, int b) {e.push_back({b, h[a]});h[a] = e.size() - 1;
}void Tarjan(int u, int in_edge) {low[u] = dfn[u] = ++tot;stk.push(u);for(int i = h[u]; ~i; i = e[i].ne) {int v = e[i].v;if(!dfn[v]) {Tarjan(v, i);low[u] = std::min(low[u], low[v]);if(low[v] > dfn[u]) bri[i] = bri[i ^ 1] = true;}else if(i != (in_edge ^ 1)) low[u] = std::min(low[u], dfn[v]);}if(low[u] == dfn[u]) {int v;cnt++;do{v = stk.top();stk.pop();dcc[v] = cnt;}while(v != u);}
}inline int BFS(int root) {dist.assign(cnt + 1, INF);q = std::queue<int>();int max_num = root, max_dist = 0;q.push(root);dist[root] = 0;while(!q.empty()) {int u = q.front();q.pop();for(const int& v : tree[u]) {if(dist[v] == INF) { // 没走过dist[v] = dist[u] + 1;if(dist[v] > max_dist) {max_dist = dist[v];max_num = v;}q.push(v);}}}return max_num;
}inline void BFS(int u, int v) { // 重载dist.assign(cnt + 1, INF);q = std::queue<int>();q.push(u);dist[u] = 0;while(!q.empty()) {int now = q.front();q.pop();for(const int& ne : tree[now]) {if(dist[ne] == INF) {dist[ne] = dist[now] + 1;q.push(ne);}}}std::cout << dist[v] << '\n';
}int main(void) {std::ios::sync_with_stdio(false);std::cin.tie(nullptr), std::cout.tie(nullptr);std::cin >> n >> m;low.resize(n + 1);dfn.resize(n + 1);dcc.resize(n + 1);h.resize(n + 1, -1);bri.resize(2 * m + 1, false);rep(i, m) {int x, y;std::cin >> x >> y;add(x, y);add(y, x);}Rep(i, 1, n + 1) if(!dfn[i]) Tarjan(i, -1);if(cnt <= 1) {std::cout << 0 << '\n';return 0;}tree.resize(cnt + 1);Rep(u, 1, n + 1) {for(int i = h[u]; ~i; i = e[i].ne) {int v = e[i].v;if(bri[i]) {int nu = dcc[u], nv = dcc[v];if(nu == nv) continue;tree[nu].push_back(nv);tree[nv].push_back(nu);}}}// 计算树的直径int u = BFS(1);int v = BFS(u);BFS(u, v);return 0;
}

一些问题:
Q:为什么 u 到 v 是必经过的最长路径(树的直径)?
A:
代码中通过两次 BFS 来求树的直径。首先从任意一个点(这里是 1)开始进行 BFS,找到离这个点最远的点 u。然后从 u 点再次进行 BFS,找到离 u 最远的点 v。

根据树的直径的性质,对于一棵树,从任意一个点出发找到的最远点一定是直径的一个端点。所以第一次 BFS 找到的 u 是直径的一个端点。然后从 u 出发再次进行 BFS 找到的 v 就是直径的另一个端点。

这样 u 到 v 的路径就是这棵树的直径,因为树的直径定义为树中任意两点间距离的最大值,而通过上述两次 BFS 的方法保证了找到的 u 和 v 之间的路径是树中最长的路径。

Q:在原图中的意义(边双连通分量的角度)?
A:在原图中,边双连通分量内部是没有桥的,而桥连接了不同的边双连通分量。通过求缩点后树的直径,实际上是找到了原图中通过桥连接的两个最远的边双连通分量。u 到 v 的路径上经过的桥是原图中连接不同边双连通分量的关键路径。
Q:树的直径(u 到 v 的路径)在原图中的意义是:
A:最长的桥路径:直径路径上的边都是原图中的桥,这条路径是原图中通过桥连接的最长路径。
必经的关键路径:在原图中,如果要从一个边双连通分量到达另一个边双连通分量,必须通过它们之间的桥。直径路径代表了原图中最远的两个边双连通分量之间的必经之路。
Q:为什么这就是问题的解?
A:直径路径上的桥是原图中连接不同边双连通分量的关键路径。
任何跨越多个边双连通分量的路径都必须经过这些桥。因此,树的直径长度就代表了原图中两个最远的边双连通分量之间的最短路径长度(因为每次跨越一个桥算一步)。

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

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

相关文章

imx6uLL应用-v4l2

Linux V4L2 视频采集 JPEG 解码 LCD 显示实践 本文记录一个完整的嵌入式视频处理项目&#xff1a;使用 V4L2 接口从摄像头采集 MJPEG 图像&#xff0c;使用 libjpeg 解码为 RGB 格式&#xff0c;并通过 framebuffer 显示在 LCD 屏幕上。适用于使用 ARM Cortex-A 系列开发板进…

强化学习机器人模拟器——QAgent:一个支持多种强化学习算法的 Python 实现

QAgent 是一个灵活的 Python 类,专为实现经典的强化学习(Reinforcement Learning, RL)算法而设计,支持 Q-learning、SARSA 和 SARSA(λ) 三种算法。本篇博客将基于提供的 q_agent.py 代码,详细介绍 QAgent 类的功能、结构和使用方法,帮助您理解其在强化学习任务中的应用,…

Feign的原理

为什么 SpringCloud 中的Feign&#xff0c;可以帮助我们像使用本地接口一样调用远程 HTTP服务&#xff1f; Feign底层是如何实现的&#xff1f;这篇文章&#xff0c;我们一起来聊一聊。 1. Feign 的基本原理 Feign 的核心思想是通过接口和注解定义 HTTP 请求&#xff0c;将接…

探索正态分布:交互式实验带你体验统计之美

探索正态分布&#xff1a;交互式实验带你体验统计之美 正态分布&#xff0c;这条优美的钟形曲线&#xff0c;可以说是统计学中最重要、最无处不在的概率分布。从自然现象&#xff08;如身高、测量误差&#xff09;到金融市场&#xff0c;再到机器学习&#xff0c;它的身影随处…

使用 IDEA + Maven 搭建传统 Spring MVC 项目的详细步骤(非Spring Boot)

搭建Spring MVC项目 第一步&#xff1a;创建Maven项目第二步&#xff1a;配置pom.xml第三步&#xff1a;配置web.xml第四步&#xff1a;创建Spring配置文件第五步&#xff1a;创建控制器第六步&#xff1a;创建JSP视图第七步&#xff1a;配置Tomcat并运行目录结构常见问题解决与…

AI日报 · 2025年5月04日|Hugging Face 启动 MCP 全球创新挑战赛

1、Hugging Face 启动 MCP 全球创新挑战赛 Hugging Face 于 5 月 3 日发布 MCP Global Innovation Challenge&#xff0c;面向全球开发者征集基于模型上下文协议&#xff08;MCP&#xff09;的创新工具与应用&#xff0c;赛事持续至 5 月 31 日&#xff0c;设立多档…

学习spring boot-拦截器Interceptor,过滤器Filter

目录 拦截器Interceptor 过滤器Filter 关于过滤器的前置知识可以参考&#xff1a; 过滤器在springboot项目的应用 一&#xff0c;使用WebfilterServletComponentScan 注解 1 创建过滤器类实现Filter接口 2 在启动类中添加 ServletComponentScan 注解 二&#xff0c;创建…

汇编常用语法

GNU汇编语句&#xff1a; [lable:] instruction [comment] lable 表示标号&#xff0c;表示地址位置&#xff0c;可选. instruction即指令&#xff0c;也就是汇编指令或伪指令。 comment 就是注释内容。 用户使用.section 伪操作来定义一个段&#xff0c;汇编系统预定义了一些…

terraform resource创建了5台阿里云ecs,如要使用terraform删除其中一台主机,如何删除?

在 Terraform 中删除阿里云 5 台 ECS 实例中的某一台&#xff0c;具体操作取决于你创建资源时使用的 多实例管理方式&#xff08;count 或 for_each&#xff09;。以下是详细解决方案&#xff1a; 方法一&#xff1a;使用 for_each&#xff08;推荐&#xff09; 如果创建时使…

pycharm terminal 窗口打不开了

参考添加链接描述powershell.exe改为cmd.exe发现有一个小正方形&#xff0c;最大化可以看见了。

百度「心响」:左手“多智能体”右手“保姆级服务”,C端用户能看懂这技术告白吗?

——当技术名词撞上“傻瓜式”需求&#xff0c;谁是赢家&#xff1f; 「多智能体」是什么&#xff1f;用户&#xff1a;不重要&#xff0c;能一键搞定就行 百度最新推出的多智能体平台“心响”&#xff0c;号称能用自然语言交互一键托管复杂任务。 从旅游攻略到法律咨询&#x…

57认知干货:AI机器人产业

机器人本质上由可移动的方式和可交互万物的机构组成,即适应不同环境下不同场景的情况,机器人能够做到根据需求调整交互机构和移动方式。因此,随着人工智能技术的发展,AI机器人的产业也将在未来逐步从单一任务的执行者,发展为能够完成复杂多样任务的智能体。 在未来的社会…

在两个bean之间进行数据传递的解决方案

简介 在日常开发中&#xff0c;在两个bean之间进行数据传递是常见的操作&#xff0c;例如在日常开发中&#xff0c;将数据从VO类转移到DO类等。在两个bean之间进行数据传递&#xff0c;最常见的解决方案&#xff0c;就是手动复制&#xff0c;但是它比较繁琐&#xff0c;充斥着…

基于开闭原则优化数据库查询语句拼接方法

背景 在开发实践中&#xff0c;曾有同事在实现新功能时&#xff0c;因直接修改一段数据库查询条件拼接方法的代码逻辑&#xff0c;导致生产环境出现故障。 具体来看&#xff0c;该方法通过在函数内部直接编写条件判断语句实现查询拼接&#xff0c;尽管从面向对象设计的开闭原…

QT开发工具对比:Qt Creator、Qt Designer、Qt Design Studio

前端开发工具—Qt Designer Qt Designer是Qt框架的一部分&#xff0c;是一个图形用户界面设计工具。它允许开发者通过可视化方式设计和布局GUI组件&#xff0c;而无需手动编写UI代码。设计完成后&#xff0c;Qt Designer生成UI文件&#xff08;通常以.ui为扩展名&#xff09;&…

0基础 | STM32 | TB6612电机驱动使用

TB6612介绍及使用 单片机通过驱动板连接至电机 原因&#xff1a;单品机I/O口输出电流I小 驱动板&#xff1a;从外部引入高电压&#xff0c;控制电机驱动 电源部分 VM&#xff1a;电机驱动电源输入&#xff0c;输入电压范围建议为3.7&#xff5e;12V GND&#xff1a;逻辑电…

【操作系统】死锁

1. 定义 死锁是指两个或多个进程&#xff08;或线程&#xff09;在执行过程中&#xff0c;因争夺资源而造成的一种僵局&#xff0c;每个进程都无限期地等待其他进程释放它们所持有的资源。在这种情况下&#xff0c;没有任何进程能够继续执行&#xff0c;除非有外部干预。 2. …

C++入门☞关于类的一些特殊知识点

涉及的关于类中的默认成员函数的知识点可以看我的这篇博客哦~ C入门必须知道的知识☞类的默认成员函数&#xff0c;一文讲透运用 目录 初始化列表 类型转换 static成员 友元 内部类 匿名对象 对象拷贝时的一些编译器的优化 初始化列表 我们知道类中的构造函数的任务是完…

只用Prettier进行格式化项目

1.下载Prettier插件&#xff0c;禁用ESlint 2.在项目根目录新建.prettierrc文件 {"singleQuote": true,"jsxSingleQuote": true,"printWidth": 100,"trailingComma": "none","tabWidth": 2,"semi": f…

XXL-TOOL v1.4.0 发布 | Java工具类库

Release Notes 1、【新增】JsonRpc模块&#xff1a;一个轻量级、跨语言远程过程调用实现&#xff0c;基于json、http实现&#xff08;从XXL-JOB底层通讯组件提炼抽象&#xff09;。2、【新增】Concurrent模块&#xff1a;一系列并发编程工具&#xff0c;具备良好的线程安全、高…