【洛谷 P8604】[蓝桥杯 2013 国 C] 危险系数 题解(Tarjan算法+无向图+求割点+链式前向星+广度优先搜索)

本文主要是介绍【洛谷 P8604】[蓝桥杯 2013 国 C] 危险系数 题解(Tarjan算法+无向图+求割点+链式前向星+广度优先搜索),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[蓝桥杯 2013 国 C] 危险系数

题目背景

抗日战争时期,冀中平原的地道战曾发挥重要作用。

题目描述

地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。

我们来定义一个危险系数 D F ( x , y ) DF(x,y) DF(x,y)

对于两个站点 x x x y ( x ≠ y ) , y(x\neq y), y(x=y), 如果能找到一个站点 z z z,当 z z z 被敌人破坏后, x x x y y y 不连通,那么我们称 z z z 为关于 x , y x,y x,y 的关键点。相应的,对于任意一对站点 x x x y y y,危险系数 D F ( x , y ) DF(x,y) DF(x,y) 就表示为这两点之间的关键点个数。

本题的任务是:已知网络结构,求两站点之间的危险系数。

输入格式

输入数据第一行包含 2 2 2 个整数 n ( 2 ≤ n ≤ 1000 ) n(2 \le n \le 1000) n(2n1000) m ( 0 ≤ m ≤ 2000 ) m(0 \le m \le 2000) m(0m2000),分别代表站点数,通道数。

接下来 m m m 行,每行两个整数 u , v ( 1 ≤ u , v ≤ n , u ≠ v ) u,v(1 \le u,v \le n,u\neq v) u,v(1u,vn,u=v) 代表一条通道。

最后 1 1 1 行,两个数 u , v u,v u,v,代表询问两点之间的危险系数 D F ( u , v ) DF(u,v) DF(u,v)

输出格式

一个整数,如果询问的两点不连通则输出 − 1 -1 1

样例 #1

样例输入 #1

7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6

样例输出 #1

2

提示

时限 1 秒, 64M。蓝桥杯 2013 年第四届国赛


思路

先用Tarjan算法求割点,再用广度优先搜索求关键点。

Tarjan函数用于在图中找出所有的割点。割点是指,如果去掉这个点以及与它相连的边,会使得原本连通的图不再连通。Tarjan函数通过深度优先搜索(DFS)的方式来找出所有的割点。

对每个节点,将其深度优先搜索序号dfn和最早可回溯的节点序号low都初始化为0。如果它还未被访问过,则调用深度优先搜索。在搜索的过程中,维护一个全局的时间戳num,代表当前的搜索次序。每当访问到一个新的节点,就将其dfn和low值都设置为当前的时间戳,并将时间戳加1。

在深度优先搜索的过程中,如果遍历到一个子节点v,而这个子节点已经被访问过,那么就尝试用这个子节点的dfn值更新当前节点u的low值,即low[u] = min(low[u], dfn[v])。这一步表示,如果存在一个从u出发的回路可以回到v,那么u就可以通过这个回路回到v。

如果遍历到一个子节点v,而这个子节点还未被访问过,那么就对v进行深度优先搜索。在搜索结束后,尝试用v的low值更新u的low值,即low[u] = min(low[u], low[v])。这一步表示,如果v可以回到的最早的节点也可以被u到达,那么u就可以通过v回到这个节点。

在对一个节点u的所有子节点遍历结束后,检查是否存在一个子节点v,使得low[v] >= dfn[u]。如果存在,那么u就是一个割点。

bfs函数用来判断在移除特定节点后,起点和终点是否仍然连通。通过广度优先搜索,从起点开始,遍历所有可以到达的节点。

首先清空队列和访问标记位集,然后将起点加入队列。然后进行循环,每次从队列中取出一个节点,标记为已访问,然后遍历这个节点的所有邻接节点。

对于每一个邻接节点,如果它是终点,那么就返回true,表示起点和终点是连通的。如果这个邻接节点没有被访问过,并且不是被移除的节点,那么就将它加入到队列中。如果在遍历过程中没有找到终点,那么就返回false,表示起点和终点不连通。

注意

  1. 若起点就是终点,危险系数就是0,直接输出0即可。
  2. 需要判断起点和终点是否连通。若不连通,直接输出-1即可。
  3. 割点不一定是关键点,有可能存在这样的情况:路径上某个点是割点,但是移除该点后,仍能通过其他路径能到达终点。需要对每个割点进行判断,若移除该割点后无法到达终点的,才是路径上的关键点。举个例子:

样例输入

13 13
1 3
2 3
3 4
3 5
4 5
5 6
5 11
11 12
12 13
13 7
7 10
6 7
8 6
1 10

样例输出

3

对于这组样例数据,节点3、5、6和7是割点。节点6是一个割点,但不是路径(1到10)的关键点。因此,答案是3而不是4。

1
2
3
4
5
6
7
8
10
11
12
13

AC代码

#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;const int N = 1e6 + 7;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;struct Node {int to;int next;
} edge[N];
int head[N];
int cnt = 0;int n, m;
int qu, qv;// tarjan
int num = 0;
int dfn[N], low[N];
bitset<N> cut;// bfs
queue<int> q1;
bitset<N> vis;void init() {cut.reset();memset(head, -1, sizeof(head));memset(dfn, 0, sizeof(dfn));memset(low, 0, sizeof(low));
}void add(int u, int v) {edge[cnt].to = v;edge[cnt].next = head[u];head[u] = cnt++;
}// 求割点
void tarjan(int u, int fa) {// 初始化dfn[u] = low[u] = ++num;int son = 0;for (int i = head[u]; ~i; i = edge[i].next) {int v = edge[i].to;if (v == fa) {continue;}if (!dfn[v]) {// 访问子节点tarjan(v, u);// 回溯时更新low[u] = min(low[u], low[v]);if (low[v] >= dfn[u]) {son++;if (u != fa || son > 1) {// u不是根节点或有两个以上子节点满足条件cut[u] = 1;}}} else {// 回溯时更新low[u] = min(low[u], dfn[v]);}}
}bool bfs(int rm) {// 初始化vis.reset();while (q1.size()) {q1.pop();}q1.push(qu);while (q1.size()) {int f = q1.front();// cout << f << endl;q1.pop();vis[f] = 1;for (int i = head[f]; ~i; i = edge[i].next) {int to = edge[i].to;if (to == qv) {// 能到达return 1;}if (vis[to] || to == rm) {continue;}// cout << to << " " << cut[to] << endl;q1.push(to);}}return 0;
}int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);init();cin >> n >> m;for (int i = 1; i <= m; i++) {int u, v;cin >> u >> v;add(u, v);add(v, u);}cin >> qu >> qv;if (qu == qv) {// 若起点就是终点,危险系数就是0。cout << 0 << "\n";return 0;}// 求割点tarjan(qu, qu);if (!bfs(0)) {// 起点和终点不连通,无法到达cout << -1 << "\n";return 0;}ll ans = 0;// 找出路径上的关键点for (int i = 1; i <= n; i++) {if (cut[i] && !bfs(i)) {// 移除该割点后无法到达终点的才是路径上的关键点ans++;}}cout << ans << "\n";return 0;
}

这篇关于【洛谷 P8604】[蓝桥杯 2013 国 C] 危险系数 题解(Tarjan算法+无向图+求割点+链式前向星+广度优先搜索)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/861202

相关文章

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

C# ComboBox下拉框实现搜索方式

《C#ComboBox下拉框实现搜索方式》文章介绍了如何在加载窗口时实现一个功能,并在ComboBox下拉框中添加键盘事件以实现搜索功能,由于数据不方便公开,作者表示理解并希望得到大家的指教... 目录C# ComboBox下拉框实现搜索步骤一步骤二步骤三总结C# ComboBox下拉框实现搜索步骤一这

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

hdu1240、hdu1253(三维搜索题)

1、从后往前输入,(x,y,z); 2、从下往上输入,(y , z, x); 3、从左往右输入,(z,x,y); hdu1240代码如下: #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#inc

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig