tarjan算法之 割边,割点
2015-08-07 16:07
302 查看
先介绍几个概念:
1.割边:在连通图中,删除了连通图的某条边后,图不再连通。,这样的边叫做割边,也称作桥。
2.割点:在连通图中,删除了连通图的某个点以及与这个点相连的边后,图不再连通。这样的点叫做割点。
3.dfs搜索树:用 dfs 遍历图时,按照遍历次序的不同,我们可以得到一颗 dfs 搜索树。
举个例子,对这个图一来说,其dfs搜索树便是图二
图中还有几个概念
树边:在搜索树中实线所示,表示dfs过程中访问 未访问结点 时所经过的边,也叫父子边
回边:在搜索树中虚线所示,表示dfs过程中遇到 已访问结点 时所经过的边,也叫返祖边、后向边。
割点包含两类结点:
1.对于根节点u,如果u有不止一棵子树(两棵及两棵以上),则该跟节点u为割点
2.对于非叶子且非根结点(叶子结点一定不是割点),若其中的某棵子树的结点均没有指向u的祖先结点的回边,说明删除u之后,根节点与该棵子树的结点不再连通,则结点 u 为割点。
我们用dfn[u]数组来记录u结点的dfs次序,low[u]来记录结点 u 或 u 的子树通过非父子边(这里的子指的是u,父指的是u的父亲结点)追溯到最早的祖先结点(dfs次序最小的结点),那么low[u]可以这么得到
若(u,v)是树边,则low[u]=min(low[u],low[v]);
若(u,v)是回边且v不是u的父亲,则low[u]=min(low[u],dfs[v]);
对于图一,dfn和low数组分别为
对于割点的第一种情况,很容易判断子树的个数,用child变量记录一下就好了
对于割点的第二种情况,当(u,v)为树边且low[v]>=dfn[u]时,结点u才是割点。
而对于割边,当(u,v)为树边且dfs[u]>low[v]时,表示v结点智能通过该边(u,v)与u连通,那么(u,v)即为割边。
1.割边:在连通图中,删除了连通图的某条边后,图不再连通。,这样的边叫做割边,也称作桥。
2.割点:在连通图中,删除了连通图的某个点以及与这个点相连的边后,图不再连通。这样的点叫做割点。
3.dfs搜索树:用 dfs 遍历图时,按照遍历次序的不同,我们可以得到一颗 dfs 搜索树。
举个例子,对这个图一来说,其dfs搜索树便是图二
图中还有几个概念
树边:在搜索树中实线所示,表示dfs过程中访问 未访问结点 时所经过的边,也叫父子边
回边:在搜索树中虚线所示,表示dfs过程中遇到 已访问结点 时所经过的边,也叫返祖边、后向边。
割点包含两类结点:
1.对于根节点u,如果u有不止一棵子树(两棵及两棵以上),则该跟节点u为割点
2.对于非叶子且非根结点(叶子结点一定不是割点),若其中的某棵子树的结点均没有指向u的祖先结点的回边,说明删除u之后,根节点与该棵子树的结点不再连通,则结点 u 为割点。
我们用dfn[u]数组来记录u结点的dfs次序,low[u]来记录结点 u 或 u 的子树通过非父子边(这里的子指的是u,父指的是u的父亲结点)追溯到最早的祖先结点(dfs次序最小的结点),那么low[u]可以这么得到
若(u,v)是树边,则low[u]=min(low[u],low[v]);
若(u,v)是回边且v不是u的父亲,则low[u]=min(low[u],dfs[v]);
对于图一,dfn和low数组分别为
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
dfn | 1 | 3 | 5 | 2 | 4 | ||
low | 1 | 3 | 3 | 2 | 3 |
对于割点的第二种情况,当(u,v)为树边且low[v]>=dfn[u]时,结点u才是割点。
而对于割边,当(u,v)为树边且dfs[u]>low[v]时,表示v结点智能通过该边(u,v)与u连通,那么(u,v)即为割边。
#pragma warning(disable:4996) #include <cstdio> #include <vector> #include <cstring> #include <set> #include <algorithm> #define make_pair pair<int,int> #define N 20010 using namespace std; vector<int>to ; vector<pair<int, int>>line;//存割边 set<int>ans;//存割点 int father ; // 0 表示根节点,-1 表示未遍历, 否则代表父亲结点 //dfn[u]数组表示结点 u 的dfs遍历次序,low[u]数组表示 u 及其子树能到达的最远祖宗结点 int dfn , low , dfs_clock = 0; void init(){ dfs_clock = 0; memset(father, -1, sizeof father); father[1] = 0; } void dfs(int u){ dfn[u] = low[u] = ++dfs_clock; int child = 0; for (int i = 0; i < to[u].size(); i++){ int v = to[u][i]; //未访问过 v 点 if (father[v] == -1){ child++; father[v] = u; dfs(v); low[u] = min(low[u], low[v]); //结点 u 是根节点,且有不止一个子树 if (father[u] == 0 && child>1) ans.insert(u); //结点 u 不是根节点, if (father[u] != 0 && dfn[u] <= low[v]) ans.insert(u); //割边的情况 if (low[v] > dfn[u])line.push_back(make_pair(min(u, v), max(u, v))); } else if (father[u] != v){ low[u] = min(low[u], dfn[v]); } } }
相关文章推荐
- hdu_1166
- 第六篇:C++语言源程序中每一行加一个反斜杠的意思
- 【机房收费系统】登陆界面
- c++ 内存池
- IntelliJ IDEA部署web程序图文教程
- HDU 5339 Untitled(暴搜)
- PHP curl 模拟登录并获取数据
- 数据中心分解实验(三)-N5K
- iOS UITableViewCell重用问题
- 杭电acm 2162 Add ‘em
- 对于生产者消费者模型的理解
- hdu1686 oulipo 【KMP】
- AXIS调用jws发布的webservice出现Cannot find dispatch method for
- Windows Azure入门教学系列 (一): 创建第一个WebRole程序
- 多维DP UVA 11552 Fewest Flop
- 打印N字形
- UVa 10010 Where's Waldorf?
- qt 选择文件夹下的文件复制
- dede如何对描述字符description限制字数
- ReactiveMongo 学习笔记