码迷,mamicode.com
首页 > 其他好文 > 详细

tarjan求割边割点

时间:2017-04-18 09:34:55      阅读:219      评论:0      收藏:0      [点我收藏+]

标签:point   view   main   gif   first   访问   int   images   clu   

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=0;
 6 int low[20004],dfn[20004],father[20004],son[20004];
 7 //father:父结点 son:子结点个数 
 8 vector<int> cutpoint,edge[20004];
 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=0;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]==0&&son[u]>1)||(father[u]&&flag)) cutpoint.push_back(u);
34 }
35 
36 int main()
37 {
38     scanf("%d%d",&n,&m);
39     for (int i=1;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(1);
46     sort(cutedge.begin(),cutedge.end());
47     sort(cutpoint.begin(),cutpoint.end());
48     if(0==cutpoint.size()) puts("Null");
49     else
50     {
51         printf("%d",cutpoint[0]);
52         for (int i=1;i<cutpoint.size();i++) printf(" %d",cutpoint[i]);
53         puts("");
54     }
55     for(int i=0;i<cutedge.size();i++) printf("%d %d\n",cutedge[i].first,cutedge[i].second);
56 }
View Code

 

tarjan求割边割点

标签:point   view   main   gif   first   访问   int   images   clu   

原文地址:http://www.cnblogs.com/jsawz/p/6726053.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!