求无向图的割点和桥模板(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,他对 ...
随机推荐
- 实现单击列表头对ListView的动态排序
排序是根据列的类型来的,就ID列来说,int类型的排序结果是3,5,17,而如果你把该列类型改为string,结果就会是17,3,5,如果你定义列的时候不加类型,默认是string,如果是自定义类型, ...
- 简单label控件 自制
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using ...
- 九度OJ 1141:Financial Management (财务管理) (平均数)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:939 解决:489 题目描述: Larry graduated this year and finally has a job. He's ...
- ALTER USER USER() IDENTIFIED BY 'password';
[root@test mysql]# bin/mysqld 2018-08-04T14:09:33.831318Z 0 [Warning] [MY-011070] [Server] 'Disablin ...
- mysql 5.6 bug
https://dev.mysql.com/doc/refman/5.6/en/account-management-sql.html USE mysql; SELECT Host,User FROM ...
- 建立FTP服务器(FTP服务器名要与创建的用户名一致)
1新建用户 2. 3.建立FTP
- Objective-C 学习笔记
1. Hello, World #import <Foundation/Foundation.h> int main() { /* my first program in Objec ...
- uboot之logo显示【转】
本文转载自:http://blog.csdn.net/tuwenqi2013/article/details/60583735 版权声明:本文为博主原创文章,博主欢迎各位转载. 一.logo的调用流程 ...
- js正则表达式,密码长度要大于6位,由数字和字母组成
var pwd = $("#pwd").val(); var reg = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,}$/; if(!reg ...
- SQL server 备份/恢复/压缩 进度查询
第一步,用 sp_who2 查出备份的sid(或在窗口中的连接属性中看) exec sp_who2 第二步,用以下查询获得运行情况(看 percent_complete列) SELECT sessio ...