求无向图的割点和桥模板(tarjan)
一.基本概念
1.桥:若无向连通图的边割集中只有一条边,则称这条边为割边或者桥 (离散书上给出的定义。。
通俗的来说就是无向连通图中的某条边,删除后得到的新图联通分支至少为2(即不连通;
2.割点:若无向连通图的点割集中只有一个点,则称这个点为割点或者关节点 ;
通俗的来说就是无向连通图中的某条边,删除后得到的新图连通分支至少为2;
二:tarjan算法求割点和桥
1.割点:1)当前节点为树根的时候,条件是“要有多余一棵子树”;
如果这有一颗子树,去掉这个点也没有影响,如果有两颗子树,去掉这点,两颗子树就不连通了;
2)当前节点u不是树根的时候,条件是“low[v]>=dfn[u]”,也就是在u之后遍历的点,能够向上翻,
最多到u,如果能翻到u的上方,那就有环了,去掉u之后,图仍然连通。
2.桥:若一条无向边(u,v)是桥,
1)当且仅当无向边(u,v)是树枝边,需要满足dfn(u)<low(v),即v向上翻不到u及其以上的点,
那么u--v之间一定能够有1条或者多条边不能删去, 因为他们之间有部分无环,是桥,
如果v能上翻到u那么u--v就是一个环,删除其中一条路径后,仍然是连通的。
3.注意点:1)求桥的时候:因为边是无方向的,所以父亲孩子节点的关系需要自己规定一下,
在tarjan的过程中if(v不是u的父节点) low[u]=min(low[u],dfn[v]);
因为如果v是u的父亲,那么这条无向边就被误认为是环了。
2)找桥的时候:注意看看有没有重边,有重边的边一定不是桥,也要避免误判。
4.也可以先进行tarjan(),求出每一个点的dfn和low,并记录dfs过程中的每个点的父节点,
遍历所有点的low,dfn来寻找桥和割点
代码:
#include <iostream>
#include <stdio.h>
#include <vector>
#include <string.h>
using namespace std; const int MAXN=1e5+;
vector<int> mp[MAXN];
bool is_cut[MAXN];
int n, m, count=;
int low[MAXN], dfn[MAXN], pre[MAXN];//pre[u]记录u的父亲节点编号
//dfn[u]记录节点u在DFS过程中被遍历到的次序号,low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小 void tarjan(int u, int fu){
pre[u]=fu;//记录当前u的父亲节点
dfn[u]=low[u]=count++;
for(int i=; i<mp[u].size(); i++){
int v=mp[u][i];
if(dfn[v]==-){
tarjan(v, u);
low[u]=min(low[u], low[v]);
}else if(fu!=v){//如果v是u的父亲的话,即有重边,那么不可能是桥
low[u]=min(low[u], dfn[v]);
}
}
} void solve(void){
int rootson=;
tarjan(, );
for(int i=; i<=n; i++){
int v=pre[i];
if(v==){
rootson++;//统计根节点的子树个数,若其不小于2,即为割点
}else if(low[i]>=dfn[v]){
is_cut[v]=true;
}
}
if(rootson>) is_cut[]=true;
puts("割点为:");
for(int i=; i<=n; i++){//输出割点
if(is_cut[i]){
printf("%d ", i);
}
}
puts("\n桥为:");
for(int i=; i<=n; i++){
int v=pre[i];
if(v>&&low[i]>dfn[v]){
printf("%d %d\n", v, i);
}
}
puts("");
} int main(void){
scanf("%d%d", &n, &m);
for(int i=; i<m; i++){
int x, y;
scanf("%d%d", &x, &y);
mp[x].push_back(y);
mp[y].push_back(x);
}
memset(dfn, -, sizeof(dfn));
memset(low, -, sizeof(low));
solve();
return ;
}
求桥的另一种写法(更快一点):
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std; const int MAXN = 1e5 + ; struct node{
int v, next, use;
}edge[MAXN << ]; bool bridge[MAXN];
int low[MAXN], dfn[MAXN], vis[MAXN];
int head[MAXN], pre[MAXN], ip, sol, count; void init(void){
memset(head, -, sizeof(head));
memset(vis, false, sizeof(vis));
memset(bridge, false, sizeof(bridge));
count = sol = ip = ;
} void addedge(int u, int v){
edge[ip].v = v;
edge[ip].use = ;
edge[ip].next = head[u];
head[u] = ip++;
} void tarjan(int u){
vis[u] = ;
dfn[u] = low[u] = count++;
for(int i = head[u]; i != -; i = edge[i].next){
if(!edge[i].use){
edge[i].use = edge[i ^ ].use = ;
int v = edge[i].v;
if(!vis[v]){
pre[v] = u;
tarjan(v);
low[u] = min(low[u], low[v]);
if(dfn[u] < low[v]){
sol++;
bridge[v] = true;
}
}else if(vis[v] == ){
low[u] = min(low[u], dfn[v]);
}
}
}
vis[u] = ;
} int main(void){
int n, m, q, x, y, cas = ;
while(~scanf("%d%d", &n, &m)){
if(!n && !m) break;
init();
for(int i = ; i < m; i++){
scanf("%d%d", &x, &y);
addedge(x, y);
addedge(y, x);
}
pre[] = ;
tarjan();
for(int i = ; i <= n; i++){
if(bridge[i]) cout << i << " " << pre[i] << endl;
}
}
return ;
}
以上参考博客:http://www.cnblogs.com/c1299401227/p/5402747.html
求无向图的割点和桥模板(tarjan)的更多相关文章
- 求 无向图的割点和桥,Tarjan模板
/* 求 无向图的割点和桥 可以找出割点和桥,求删掉每个点后增加的连通块. 需要注意重边的处理,可以先用矩阵存,再转邻接表,或者进行判重 */ const int MAXN = 10010; cons ...
- tarjan算法--求无向图的割点和桥
一.基本概念 1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不连通,则称该边为桥. 2.割点:无向连通图中 ...
- Tarjan无向图的割点和桥(割边)全网详解&;算法笔记&;通俗易懂
更好的阅读体验&惊喜&原文链接 感谢@yxc的腿部挂件 大佬,指出本文不够严谨的地方,万分感谢! Tarjan无向图的割点和桥(割边) 导言 在掌握这个算法前,咱们有几个先决条件. [ ...
- 无向图的割点和桥 tarjan 模板
#include <bits/stdc++.h> using namespace std; const int MAXN = 20005; const int MAXM = 100005; ...
- tarjan算法--求解无向图的割点和桥
1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥 也就是说 无向连通图中,如果删除某边后,图变成不连通,则称该边为桥 2.割点:无向连通图中,如 ...
- 【关节点+桥】关节点和桥模板 Tarjan
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; con ...
- Tarjan求无向图割点、桥详解
tarjan算法--求无向图的割点和桥 一.基本概念 1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不 ...
- [Tarjan系列] Tarjan算法求无向图的双连通分量
这篇介绍如何用Tarjan算法求Double Connected Component,即双连通分量. 双联通分量包括点双连通分量v-DCC和边连通分量e-DCC. 若一张无向连通图不存在割点,则称它为 ...
- [Tarjan系列] Tarjan算法求无向图的桥和割点
RobertTarjan真的是一个传说级的大人物. 他发明的LCT,SplayTree这些数据结构真的给我带来了诸多便利,各种动态图论题都可以用LCT解决. 而且,Tarjan并不只发明了LCT,他对 ...
随机推荐
- Unity 碰撞器
Unity引擎的碰撞器 常见的有Box Collider,Capsule Collider等等 IsTrigger(触发器) 在这些碰撞器中有一个属性 Is Trigger(是否使用触发器) 触发器事 ...
- 20160129.CCPP体系详解(0008天)
程序片段(01):函数.c+call.c+测试.cpp 内容概要:函数 ///函数.c #include <stdio.h> #include <stdlib.h> //01. ...
- Update-ServiceTemplate
1: Update a service by using conventional servicing. PS C:\> $Service = Get-SCService -Name " ...
- java jdbc dbcp连接SQL Server
使用到的jar: commons-collections-3.1.jar commons-dbcp-1.4.jar commons-pool-1.5.6.jar sqljdbc4.jar dbcp配置 ...
- jquery.vilidate的运用
vilidate是jquery的一个form表单验证插件非常实用 里面需要注意的就是remote的用法 /*验证*/$().ready(function() { $(".form_al ...
- 背包九讲PDF
本资料仅限个人学习交流使用,不得用于商业用途. 背包九讲PDF:https://pan.baidu.com/s/17rTxMwCo9iSTOW77yucdXQ 提取码:xbqa
- 前段学习的roadmap
引自http://www.cnblogs.com/IMxinu/p/9693041.html
- zabbix结合grafana打造炫酷监控界面
一.grafana介绍 grafana是一个开源的数据展示工具, 是一个开箱即用的可视化工具,具有功能齐全的度量仪表盘和图形编辑器,有灵活丰富的图形化选项,可以混合多种风格,支持多个数据源特点. za ...
- GlusterFS分布式存储学习笔记
分布式文件系统 分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源并不直接与本地节点相连,而是分布于计算网络中的一个或者多个节点的计算机上.目前意义上的分布 ...
- golang 生成图表
golang 支持生产图片的源码在下面地址可以看到: https://github.com/vdobler/chart 这个项目 的 example 目录下编译后,执行下面命令就可以生产所有它支持的图 ...