hiho图的联通性(自留)

无向图割边割点算法

而当(u,v)为树边且low[v]>dfn[u]时,表示v节点只能通过该边(u,v)与u连通,那么(u,v)即为割边。

 1 void dfs(int u) {
 2     //记录dfs遍历次序
 3     static int counter = 0;
 4
 5     //记录节点u的子树数
 6     int children = 0;
 7
 8     ArcNode *p = graph[u].firstArc;
 9     visit[u] = 1;
10
11     //初始化dfn与low
12     dfn[u] = low[u] = ++counter;
13
14     for(; p != NULL; p = p->next) {
15         int v = p->adjvex;
16
17         //节点v未被访问,则(u,v)为树边
18         if(!visit[v]) {
19             children++;
20             parent[v] = u;
21             dfs(v);
22
23             low[u] = min(low[u], low[v]);
24
25             //case (1)
26             if(parent[u] == NIL && children > 1) {
27                 printf("articulation point: %d\n", u);
28             }
29
30             //case (2)
31             if(parent[u] != NIL && low[v] >= dfn[u]) {
32                 printf("articulation point: %d\n", u);
33             }
34
35             //bridge
36             if(low[v] > dfn[u]) {
37                 printf("bridge: %d %d\n", u, v);
38             }
39         }
40
41         //节点v已访问,则(u,v)为回边
42         else if(v != parent[u]) {
43             low[u] = min(low[u], dfn[v]);
44         }
45     }
46 }

边双联通分量算法

对于一个无向图的子图,当删除其中任意一个点后,不改变图内点的连通性,这样的子图叫做点的双连通子图。而当子图的边数达到最大时,叫做点的双连通分量。

直观的做法自然先用上周的算法求出所有桥,去掉所有桥之后再做DFS求出每一个连通子图。我们这周要介绍一种更"抽象"的算法,通过在Tarjan算法当中巧妙地用一个栈来统计出每一个组内的节点,其代码如下:

 1 void dfs(int u) {
 2     //记录dfs遍历次序
 3     static int counter = 0;
 4
 5     //记录节点u的子树数
 6     int children = 0;
 7
 8     ArcNode *p = graph[u].firstArc;
 9     visit[u] = 1;
10
11     //初始化dfn与low
12     dfn[u] = low[u] = ++counter;
13
14     //将u加入栈
15     stack[++top] = u;
16
17     for(; p != NULL; p = p->next) {
18         int v = p->adjvex;
19
20         //节点v未被访问,则(u,v)为树边
21         if(!visit[v]) {
22             children++;
23             parent[v] = u;
24             dfs(v);
25
26             low[u] = min(low[u], low[v]);
27             if (low[v] > dfn[u]) {
28                 printf("bridge: %d %d\n", u, v);    // 该边是桥
29                 bridgeCnt++;
30             }
31         }
32
33         //节点v已访问,则(u,v)为回边
34         else if(v != parent[u]) {
35             low[u] = min(low[u], dfn[v]);
36         }
37     }
38
39     if (low[u] == dfn[u])
40     {
41         // 因为low[u] == dfn[u],对(parent[u],u)来说有dfn[u] > dfn[ parent[u] ],因此low[u] > dfn[ parent[u] ]
42         // 所以(parent[u],u)一定是一个桥,那么此时栈内在u之前入栈的点和u被该桥分割开
43         // 则u和之后入栈的节点属于同一个组
44         将从u到栈顶所有的元素标记为一个组,并弹出这些元素。
45     }
46 }

强连通分量

对于有向图上的2个点a,b,若存在一条从a到b的路径,也存在一条从b到a的路径,那么称a,b是强连通的。
对于有向图上的一个子图,若子图内任意点对(a,b)都满足强连通,则称该子图为强连通子图。
非强连通图有向图的极大强连通子图,称为强连通分量。
特别地,和任何一个点都不强连通的单个点也是一个强连通分量。

 1 tarjan(u)
 2 {
 3     Dfn[u]=Low[u]=++Index                      // 为节点u设定次序编号和Low初值
 4     Stack.push(u)                              // 将节点u压入栈中
 5     for each (u, v) in E                       // 枚举每一条边
 6         if (v is not visted)                   // 如果节点v未被访问过
 7             tarjan(v)                          // 继续向下找
 8             Low[u] = min(Low[u], Low[v])
 9         else if (v in Stack)                   // 如果节点v还在栈内(很重要,无向图没有这一步)
10             Low[u] = min(Low[u], Dfn[v])
11     if (Dfn[u] == Low[u])                      // 如果节点u是强连通分量的根
12         repeat
13             v = Stack.pop                      // 将v退栈,为该强连通分量中一个顶点
14             mark v                             // 标记v,同样通过栈来找连通分量
15         until (u == v)
16 }

scc + 缩点 + topo

点的双连通分量

对于一个无向图的子图,当删除其中任意一个点后,不改变图内点的连通性,这样的子图叫做点的双连通子图。而当子图的边数达到最大时,叫做点的双连通分量。

                                       

对于桥的两种情况,它分割个区域数刚好就等于割点数+1;而连通分量内的割点同样也是,每存在一个割点,点的双连通分量就增加一个。

点的双连通分量就等于割点数量加1。

每存在一个割点,就把一个区域一分为二,所以最后的结果也就是统计割点的数量就可以了。而对于分组具体情况,我们仍然采用栈来辅助我们记录

 1 void dfs(int u) {
 2     //记录dfs遍历次序
 3     static int counter = 0;
 4
 5     //记录节点u的子树数
 6     int children = 0;
 7
 8     ArcNode *p = graph[u].firstArc;
 9     visit[u] = 1;
10
11     //初始化dfn与low
12     dfn[u] = low[u] = ++counter;
13
14     for(; p != NULL; p = p->next) {
15         int v = p->adjvex;
16         if(edge(u,v)已经被标记) continue;
17
18         //节点v未被访问,则(u,v)为树边
19         if(!visit[v]) {
20             children++;
21             parent[v] = u;
22             edgeStack[top++] = edge(u,v); // 将边入栈
23             dfs(v);
24
25             low[u] = min(low[u], low[v]);
26
27             //case (1)
28             if(parent[u] == NIL && children > 1) {
29                 printf("articulation point: %d\n", u);
30                 // mark edge
31                 // 将边出栈,直到当前边出栈为止,这些边标记为同一个组
32                 do {
33                     nowEdge = edgeStack[top];
34                     top--;
35                     // 标记nowEdge
36                 }    while (nowEdge != edge(u,v))
37             }
38
39             //case (2)
40             if(parent[u] != NIL && low[v] >= dfn[u]) {
41                 printf("articulation point: %d\n", u);
42                 // mark edge
43                 // 将边出栈,直到当前边出栈为止,这些边标记为同一个组
44                 do {
45                     nowEdge = edgeStack[top];
46                     top--;
47                     // 标记nowEdge
48                 }    while (nowEdge != edge(u,v))
49             }
50
51         }
52
53         //节点v已访问,则(u,v)为回边
54         else if(v != parent[u]) {
55             edgeStack[top++] = edge(u,v);
56             low[u] = min(low[u], dfn[v]);
57         }
58     }
59 }

时间: 2024-10-05 06:40:54

hiho图的联通性(自留)的相关文章

图的联通性

图的联通性 0.[前置知识] 图上dfs相关概念 vis数组:在图的遍历中,往往设置了一个标记数组vis的bool值来记录顶点是否被访问过.但有些时候需要改变vis值的意义.令vis具有3种值并表示3种不同含义 vis = 0,表示该顶点没没有被访问 vis = 1,表示该顶点已经被访问,但其子孙后代还没被访问完,也就没从该点返回 vis = 2,表示该顶点已经被访问,其子孙后代也已经访问完,也已经从该顶点返回 可以vis的3种值表示的是一种顺序关系和时间关系. DFS过程中,对于一条边u->v

hiho欧拉路径(自留)

无向图 因为DFS本身就是一个入栈出栈的过程,所以我们直接利用DFS的性质来实现栈,其伪代码如下: DFS(u): While (u存在未被删除的边e(u,v)) 删除边e(u,v) DFS(v) End PathSize ← PathSize + 1 Path[ PathSize ] ← u 1 /** 2 2015.6.14 3 hiho一下 第五十周 4 欧拉路求路径 5 */ 6 7 #include<algorithm> 8 #include<iostream> 9 #i

图论——LCA、强联通分量、桥、割顶、二分图最大匹配、网络流

A: 交通运输线 时间限制: 5 Sec  内存限制: 128 MB 题目描述 战后有很多城市被严重破坏,我们需要重建城市.然而,有些建设材料只能在某些地方产生.因此,我们必须通过城市交通,来运送这些材料的城市.由于大部分道路已经在战争期间完全遭到破坏,可能有两个城市之间没有道路.当然在运输线中,更不可能存在圈. 现在,你的任务来了.给你战后的道路情况,我们想知道,两个城市之间是否存在道路,如果存在,输出这两个城市之间的最短路径长度. 输入 第一行一个整数Case(Case<=10)表示测试数据

AC日记——猴子 cogs 2043

2043. 猴子 ★★   输入文件:monkeya.in   输出文件:monkeya.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 有n只猴子,第一只尾巴挂在树上,剩下的n-1只,要么被其他的猴子抓住,要么抓住了其他的猴子,要么两者均有.当然一只猴子最多抓两只另外的猴子,因为只有两只猴爪子嘛.现在给出这n只猴子抓与被抓的信息,并且在某个时刻可能某只猴子会放掉它左手或右手的猴子,导致某些猴子落在地上.求每只猴子落地的时间. [输入格式] 第一行两个n,m,表示

hdu 3472 混合图的欧拉路径

HS BDC Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 964    Accepted Submission(s): 390 Problem Description IELTS is around the corner! love8909 has registered for the exam, but he still hasn’

浅谈Tarjan算法及思想

在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树.搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量.Tarjan算法有点类似于基于后序的深度遍历搜

Light OJ 1026 - Critical Links (图论-求割边, 桥)

题目大意:双向联通图, 现在求减少任意一边使图的联通性改变,按照起点从小到大列出所有这样的边 解题思路:双向边模版题 tarjan算法 代码如下: #include<bits/stdc++.h> using namespace std; const int N = 100003; vector<int>vec[N]; pair<int, int>edge[N]; int dfn[N], low[N]; int res, ans; void tarjan(int u, i

全网最!详!细!tarjan算法讲解。

全网最详细tarjan算法讲解,我不敢说别的.反正其他tarjan算法讲解,我看了半天才看懂.我写的这个,读完一遍,发现原来tarjan这么简单! tarjan算法,一个关于 图的联通性的神奇算法.基于DFS(迪法师)算法,深度优先搜索一张有向图.!注意!是有向图.根据树,堆栈,打标记等种种神(che)奇(dan)方法来完成剖析一个图的工作.而图的联通性,就是任督二脉通不通..的问题.了解tarjan算法之前你需要知道:强连通,强连通图,强连通分量,解答树(解答树只是一种形式.了解即可)不知道怎

【转载】全网最!详!细!tarjan算法讲解。

转自http://www.cnblogs.com/uncle-lu/p/5876729.html 全网最详细tarjan算法讲解,我不敢说别的.反正其他tarjan算法讲解,我看了半天才看懂.我写的这个,读完一遍,发现原来tarjan这么简单! tarjan算法,一个关于 图的联通性的神奇算法.基于DFS(迪法师)算法,深度优先搜索一张有向图.!注意!是有向图.根据树,堆栈,打标记等种种神(che)奇(dan)方法来完成剖析一个图的工作.而图的联通性,就是任督二脉通不通..的问题.了解tarja