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为例给出代码:

  1. #include<cstdio>
  2. #include<vector>
  3. #include<algorithm>
  4. using namespace std;
  5. int n,m,order=;
  6. int low[],dfn[],father[],son[];
  7. //father:父结点 son:子结点个数
  8. vector<int> cutpoint,edge[];
  9. vector< pair<int,int> > cutedge;
  10.  
  11. void tarjan(int u)
  12. {
  13. dfn[u]=low[u]=++order;
  14. bool flag=false;
  15. for (int i=;i<edge[u].size();i++)
  16. {
  17. int v=edge[u][i];
  18. if(!dfn[v])
  19. {
  20. son[u]++;
  21. father[v]=u;
  22. tarjan(v);
  23. if(low[v]>=dfn[u]) flag=true;
  24. //点u为割点
  25. if(low[v]>dfn[u]) cutedge.push_back(make_pair(min(v,u),max(v,u)));
  26. //边v-u为割边
  27. low[u]=min(low[u],low[v]);
  28. }
  29. else if(v!=father[u]) low[u]=min(low[u],dfn[v]);
  30. }
  31. //根节点若有两棵或两棵以上的子树则该为割点
  32. //非根节点若所有子树节点均没有指向u的祖先节点的回边则为割点
  33. if((father[u]==&&son[u]>)||(father[u]&&flag)) cutpoint.push_back(u);
  34. }
  35.  
  36. int main()
  37. {
  38. scanf("%d%d",&n,&m);
  39. for (int i=;i<=m;i++)
  40. {
  41. int u,v;
  42. scanf("%d%d",&u,&v);
  43. edge[u].push_back(v),edge[v].push_back(u);
  44. }
  45. tarjan();
  46. sort(cutedge.begin(),cutedge.end());
  47. sort(cutpoint.begin(),cutpoint.end());
  48. if(==cutpoint.size()) puts("Null");
  49. else
  50. {
  51. printf("%d",cutpoint[]);
  52. for (int i=;i<cutpoint.size();i++) printf(" %d",cutpoint[i]);
  53. puts("");
  54. }
  55. for(int i=;i<cutedge.size();i++) printf("%d %d\n",cutedge[i].first,cutedge[i].second);
  56. }

不过话说一整篇博客,光复制别人的东西不大好,那我就上一个自己打的链表实现的代码:

  1. #include<cstdio>
  2. #include<vector>
  3. #include<algorithm>
  4. #define N 420000
  5. using namespace std;
  6. vector<int>cutpoint;
  7. vector<pair<int,int> >cutedge;
  8. int next[N],to[N],num,head[N],dfn[N],low[N],tim,son[N],father[N],n,m,a,b;
  9. bool flag;
  10. void add(int false_from,int false_to){
  11. next[++num]=head[false_from];
  12. to[num]=false_to;
  13. head[false_from]=num;
  14. }
  15. void dfs(int x){
  16. dfn[x]=low[x]=++tim;
  17. bool flag=;
  18. for(int i=head[x];i;i=next[i]){
  19. if(!dfn[to[i]]){
  20. son[x]++;
  21. father[to[i]]=x;
  22. dfs(to[i]);
  23. if(low[to[i]]>=dfn[x])
  24. flag=;
  25. if(low[to[i]]>dfn[x])
  26. cutedge.push_back(make_pair(min(x,to[i]),max(x,to[i])));
  27. low[x]=min(low[x],low[to[i]]);
  28. }
  29. else
  30. if(father[x]!=to[i])
  31. low[x]=min(low[x],dfn[to[i]]);
  32. }
  33. if((!father[x]&&son[x]>)||(father[x]&&flag))
  34. cutpoint.push_back(x);
  35. }
  36. int main(){
  37. scanf("%d%d",&n,&m);
  38. for(int i=;i<=m;++i){
  39. scanf("%d%d",&a,&b);
  40. add(a,b);
  41. add(b,a);
  42. }
  43. dfs();
  44. sort(cutpoint.begin(),cutpoint.end());
  45. sort(cutedge.begin(),cutedge.end());
  46. printf("%d",cutpoint[]);
  47. for(int i=;i<cutpoint.size();i++)
  48. printf(" %d",cutpoint[i]);
  49. printf("\n");
  50. for(int i=;i<cutedge.size();i++)
  51. printf("%d %d\n",cutedge[i].first,cutedge[i].second);
  52. return ;
  53. }

tarjan求割边割点的更多相关文章

  1. 【NOIP训练】【Tarjan求割边】上学

    题目描述 给你一张图,询问当删去某一条边时,起点到终点最短路是否改变. 输入格式 第一行输入两个正整数,分别表示点数和边数.第二行输入两个正整数,起点标号为,终点标号为.接下来行,每行三个整数,表示有 ...

  2. ZOJ 2588 Burning Bridges (tarjan求割边)

    题目链接 题意 : N个点M条边,允许有重边,让你求出割边的数目以及每条割边的编号(编号是输入顺序从1到M). 思路 :tarjan求割边,对于除重边以为中生成树的边(u,v),若满足dfn[u] & ...

  3. [学习笔记]tarjan求割边

    上午打模拟赛的时候想出了第三题题解,可是我不会求割边只能暴力判割边了QAQ 所以,本文介绍求割边(又称桥). 的定义同求有向图强连通分量. 枚举当前点的所有邻接点: 1.如果某个邻接点未被访问过,则访 ...

  4. 图的连通性——Tarjan算法&割边&割点

    tarjan算法 原理: 我们考虑 DFS 搜索树与强连通分量之间的关系. 如果结点 是某个强连通分量在搜索树中遇到的第⼀个结点,那么这个强连通分量的其余结点肯定 是在搜索树中以 为根的⼦树中. 被称 ...

  5. Tarjan求无向图割点、桥详解

    tarjan算法--求无向图的割点和桥   一.基本概念 1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不 ...

  6. 牛客小白月赛12 I (tarjan求割边)

    题目链接:https://ac.nowcoder.com/acm/contest/392/I 题目大意:一个含有n个顶点m条边的图,求经过所有顶点必须要经过的边数. 例: 输入: 5 51 22 33 ...

  7. Light OJ 1026 - Critical Links (图论-双向图tarjan求割边,桥)

    题目大意:双向联通图, 现在求减少任意一边使图的联通性改变,按照起点从小到大列出所有这样的边 解题思路:双向边模版题 tarjan算法 代码如下: #include<bits/stdc++.h& ...

  8. POJ 3694 Network(Tarjan求割边+LCA)

    Network Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 10969   Accepted: 4096 Descript ...

  9. Burning Bridges 求tarjan求割边

    Burning Bridges 给出含有n个顶点和m条边的连通无向图,求出所有割边的序号. 1 #include <cstdio> 2 #include <cstring> 3 ...

随机推荐

  1. debug授权码

    www.vfxcx.com 704835b5c54b56426257e0742568fe54

  2. 1051 - Good or Bad DFS 记忆化搜索

    http://lightoj.com/volume_showproblem.php?problem=1051 对于每个位置,设dfs(cur, one, two)表示前i个字母,拥有辅音字母one个, ...

  3. return false 的其中一种用法

    return false 的具体是做什么的在这里就不多说了,因为我觉得我形容不明白.....避免大家弄混乱,就不给大家添麻烦了~~ 直接上例子: 1.先看看下面一段代码,指出其中的错误所在: //点击 ...

  4. UOJ#52. 【UR #4】元旦激光炮(交互)

    题意 给出三个已经排好序的数组$a, b, c$ 在$100$次询问内找出第$k$小的元素 Sol 一种很显然的$log^2n$的做法:首先在$a$中二分,然后再$b,c$中二分.这样可以得到$60$ ...

  5. this的试题

    1.var x=12; function test(){   console.log(this.x)  } test() //主体是window 2.var x=12;   function test ...

  6. Android 使用GridView+仿微信图片上传功能(附源代码)

    由于工作要求最近在使用GridView完成图片的批量上传功能,我的例子当中包含仿微信图片上传.拍照.本地选择.相片裁剪等功能,如果有需要的朋友可以看一下,希望我的实际经验能对您有所帮助. 直接上图,下 ...

  7. Visual studio每次build自动增加版本号

    关键词:visual studio,rc file,VS_VERSION_INFO,FILEVERSION,PRODUCTVERSION 目标:希望每次在vs中编译项目时,生成的可执行程序版本号自动+ ...

  8. 关于bin和obj文件夹。debug 和release的区别(转)

    关于bin和obj文件夹. 楼主hcaihao(影子男孩)2002-05-29 20:04:24 在 .NET技术 / C# 提问 VS.Net会生成bin和obj文件夹以及它们下面的Debug和Re ...

  9. ES5函数新增的方法(call、apply、bind)

    1.call()的使用<script type="text/javascript"> var obj1 = { name:'bob', fn:function(){ c ...

  10. (译文)IOS block编程指南 3 概念总览

    Conceptual Overview(概览) Block objects provide a way for you to create an ad hoc function body as an ...