tarjan求割边割点
tarjan求割边割点
内容及代码来自http://m.blog.csdn.net/article/details?id=51984469
割边:在连通图中,删除了连通图的某条边后,图不再连通。这样的边被称为割边,也叫做桥。
割点:在连通图中,删除了连通图的某个点以及与这个点相连的边后,图不再连通。这样的点被称为割点。
DFS搜索树:用DFS对图进行遍历时,按照遍历次序的不同,我们可以得到一棵DFS搜索树。
树边:在搜索树中的蓝色线所示,可理解为在DFS过程中访问未访问节点时所经过的边,也称为父子边
回边:在搜索树中的橙色线所示,可理解为在DFS过程中遇到已访问节点时所经过的边,也称为返祖边、后向边
观察DFS搜索树,我们可以发现有两类节点可以成为割点。对根节点u,若其有两棵或两棵以上的子树,则该根结点u为割点;对非叶子节点u(非根节点),若其中的某棵子树的节点均没有指向u的祖先节点的回边,说明删除u之后,根结点与该棵子树的节点不再连通;则节点u为割点。对于根结点,显然很好处理;但是对于非叶子节点,怎么去判断有没有回边是一个值得深思的问题。我们用dfn[u]记录节点u在DFS过程中被遍历到的次序号,low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小),那么low[u]的计算过程如下。
对于给的例子,其求出的dfn和low数组如下。
id 123456
dfn 123456
low 111444
可以发现,对于情况2,当(u,v)为树边且low[v]≥dfn[u]时,节点u才为割点。而当(u,v)为树边且low[v]>dfn[u]时,表示v节点只能通过该边(u,v)与u连通,那么(u,v)即为割边。tarjan算法的时间复杂度是O(n+m)的,非常快。
以hihoCoder1183为例给出代码:
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int n,m,order=;
int low[],dfn[],father[],son[];
//father:父结点 son:子结点个数
vector<int> cutpoint,edge[];
vector< pair<int,int> > cutedge; void tarjan(int u)
{
dfn[u]=low[u]=++order;
bool flag=false;
for (int i=;i<edge[u].size();i++)
{
int v=edge[u][i];
if(!dfn[v])
{
son[u]++;
father[v]=u;
tarjan(v);
if(low[v]>=dfn[u]) flag=true;
//点u为割点
if(low[v]>dfn[u]) cutedge.push_back(make_pair(min(v,u),max(v,u)));
//边v-u为割边
low[u]=min(low[u],low[v]);
}
else if(v!=father[u]) low[u]=min(low[u],dfn[v]);
}
//根节点若有两棵或两棵以上的子树则该为割点
//非根节点若所有子树节点均没有指向u的祖先节点的回边则为割点
if((father[u]==&&son[u]>)||(father[u]&&flag)) cutpoint.push_back(u);
} int main()
{
scanf("%d%d",&n,&m);
for (int i=;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
edge[u].push_back(v),edge[v].push_back(u);
}
tarjan();
sort(cutedge.begin(),cutedge.end());
sort(cutpoint.begin(),cutpoint.end());
if(==cutpoint.size()) puts("Null");
else
{
printf("%d",cutpoint[]);
for (int i=;i<cutpoint.size();i++) printf(" %d",cutpoint[i]);
puts("");
}
for(int i=;i<cutedge.size();i++) printf("%d %d\n",cutedge[i].first,cutedge[i].second);
}
不过话说一整篇博客,光复制别人的东西不大好,那我就上一个自己打的链表实现的代码:
#include<cstdio>
#include<vector>
#include<algorithm>
#define N 420000
using namespace std;
vector<int>cutpoint;
vector<pair<int,int> >cutedge;
int next[N],to[N],num,head[N],dfn[N],low[N],tim,son[N],father[N],n,m,a,b;
bool flag;
void add(int false_from,int false_to){
next[++num]=head[false_from];
to[num]=false_to;
head[false_from]=num;
}
void dfs(int x){
dfn[x]=low[x]=++tim;
bool flag=;
for(int i=head[x];i;i=next[i]){
if(!dfn[to[i]]){
son[x]++;
father[to[i]]=x;
dfs(to[i]);
if(low[to[i]]>=dfn[x])
flag=;
if(low[to[i]]>dfn[x])
cutedge.push_back(make_pair(min(x,to[i]),max(x,to[i])));
low[x]=min(low[x],low[to[i]]);
}
else
if(father[x]!=to[i])
low[x]=min(low[x],dfn[to[i]]);
}
if((!father[x]&&son[x]>)||(father[x]&&flag))
cutpoint.push_back(x);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=m;++i){
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
dfs();
sort(cutpoint.begin(),cutpoint.end());
sort(cutedge.begin(),cutedge.end());
printf("%d",cutpoint[]);
for(int i=;i<cutpoint.size();i++)
printf(" %d",cutpoint[i]);
printf("\n");
for(int i=;i<cutedge.size();i++)
printf("%d %d\n",cutedge[i].first,cutedge[i].second);
return ;
}
tarjan求割边割点的更多相关文章
- 【NOIP训练】【Tarjan求割边】上学
题目描述 给你一张图,询问当删去某一条边时,起点到终点最短路是否改变. 输入格式 第一行输入两个正整数,分别表示点数和边数.第二行输入两个正整数,起点标号为,终点标号为.接下来行,每行三个整数,表示有 ...
- ZOJ 2588 Burning Bridges (tarjan求割边)
题目链接 题意 : N个点M条边,允许有重边,让你求出割边的数目以及每条割边的编号(编号是输入顺序从1到M). 思路 :tarjan求割边,对于除重边以为中生成树的边(u,v),若满足dfn[u] & ...
- [学习笔记]tarjan求割边
上午打模拟赛的时候想出了第三题题解,可是我不会求割边只能暴力判割边了QAQ 所以,本文介绍求割边(又称桥). 的定义同求有向图强连通分量. 枚举当前点的所有邻接点: 1.如果某个邻接点未被访问过,则访 ...
- 图的连通性——Tarjan算法&割边&割点
tarjan算法 原理: 我们考虑 DFS 搜索树与强连通分量之间的关系. 如果结点 是某个强连通分量在搜索树中遇到的第⼀个结点,那么这个强连通分量的其余结点肯定 是在搜索树中以 为根的⼦树中. 被称 ...
- Tarjan求无向图割点、桥详解
tarjan算法--求无向图的割点和桥 一.基本概念 1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不 ...
- 牛客小白月赛12 I (tarjan求割边)
题目链接:https://ac.nowcoder.com/acm/contest/392/I 题目大意:一个含有n个顶点m条边的图,求经过所有顶点必须要经过的边数. 例: 输入: 5 51 22 33 ...
- Light OJ 1026 - Critical Links (图论-双向图tarjan求割边,桥)
题目大意:双向联通图, 现在求减少任意一边使图的联通性改变,按照起点从小到大列出所有这样的边 解题思路:双向边模版题 tarjan算法 代码如下: #include<bits/stdc++.h& ...
- POJ 3694 Network(Tarjan求割边+LCA)
Network Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 10969 Accepted: 4096 Descript ...
- Burning Bridges 求tarjan求割边
Burning Bridges 给出含有n个顶点和m条边的连通无向图,求出所有割边的序号. 1 #include <cstdio> 2 #include <cstring> 3 ...
随机推荐
- 494 Target Sum 目标和
给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S.现在你有两个符号 + 和 -.对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面.返回可以使最终数组和为 ...
- state vs props
我们来一个关于 state 和 props 的总结. state 的主要作用是用于组件保存.控制.修改自己的可变状态.state 在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改.你可以 ...
- AJPFX总结OpenJDK 和 HashMap大量数据处理时,避免垃圾回收延迟的技巧二
HashMap简史 “Hash Code”这个概念第一次出现是在1953年1月的<Computing literature>中,H. P. Luhn (1896-1964) 在一篇 IB ...
- ubuntu安装mysql多实例
想要尝试mysql的读写分离,在云上安装完mysql之后突然想到一个问题:我本机是没有公网IP的. 开始尝试在唯一一台云服务器上安装多个mysql实例. 主要步骤: 1.新建MySQL目录 (1):新 ...
- 洛谷P2770 航空路线问题(费用流)
题意 $n$个点从左向右依次排列,有$m$条双向道路 问从起点到终点,再从终点回到起点,在经过的点不同的情况下最多能经过几个点 Sol 首先,问题可以转化为求两条互不相交的路径,使得点数最多 为了满足 ...
- ES-自然语言处理
前言 自然语言处理(Natural Language Processing)是计算科学领域与人工智能领域中的一个重要方向.它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法.自然语言处理 ...
- PMP项目管理学习笔记(5)——整合管理之制定项目章程
关于两个输入 在很多过程中,会用到这两个输入: 企业环境要素 是关于你的公司如何开展业务所需要知道的所有信息. 在你计划项目时,有很多关于公司的信息会非常有用,你需要知道各个不同部门是如何运作的,你所 ...
- c# sqlserver连接字符串
odbc: string cnnstring = @"Driver={SQL Server Native Client 11.0};Initial Catalog = sxquadb;ser ...
- 一个SAP开发人员的双截棍之路
由于种种原因,Jerry最近加入了SAP成都研究院的一个演讲俱乐部,这个俱乐部主要是提高大家的英语演讲能力. 说来Jerry也是大一下期和大二上期一次性高分通过四六级考试的,但是当毕业进入SAP成都研 ...
- Ubuntu 16.04 LTS: apt-get update 失败处理 Aborted (core dumped)
在Ubuntu 16.04运行sudo apt-get update出现如下错误: rogn@ubuntu:~$ sudo apt-get update Get:1 http://us.archive ...